Coder Social home page Coder Social logo

alexeyraspopov / dataclass Goto Github PK

View Code? Open in Web Editor NEW
164.0 2.0 6.0 662 KB

Data classes for TypeScript & JavaScript

Home Page: https://dataclass.js.org

License: ISC License

JavaScript 27.04% TypeScript 72.96%
immutable data-structures javascript typescript data-class zero-dependency dataclass value-object

dataclass's Introduction

dataclass

npm install dataclass

Syntax sugar that leverages the power of available type systems in TypeScript and JavaScript to provide an effortless way for defining value objects that are immutable and persistent.

Read full docs on the website.

import { Data } from "dataclass";

class User extends Data {
  name: string = "Anon";
  age: number = 25;
}

let user = User.create({ name: "Liza", age: 23 });
// > User { name: "Liza", age: 23 }

let updated = user.copy({ name: "Ann" });
// > User { name: "Ann", age: 23 }

let isEqual = user.equals(updated);
// > false

Prior Art

The implemented concept is heavily inspired by Scala and Kotlin. Both languages have the implementation of data classes as a part of their syntax and share similar APIs.

See Data Classes in Kotlin (also Case Classes in Scala):

data class User(val name: String = "Anonymous", val age: Int = 0)

val user = User(name = "Liza", age = 23)
val updated = user.copy(name = "Ann")

user.equals(updated)

And Data Classes in Python:

from dataclasses import dataclass, replace

@dataclass
class User:
  name: str = "Anonymous"
  age: int = 0

user = User(name="Liza", age=23)
updated = replace(user, name="Ann")

user == updated

Contributing

The project is opened for any contributions (features, updates, fixes, etc). If you're interested, please check the contributing guidelines.

The project is licensed under the ISC license.

dataclass's People

Contributors

alexeyraspopov avatar mingchuno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

dataclass's Issues

[Error] Class constructor Record cannot be invoked without 'new'

Hi, i tried to use your lib in my angular4(ts) project. And I faced problem.
I defined my model as

import Record from 'dataclass';

export default class User extends Record<User> {
  id: number = 0;
  firstName: string = '';
  lastName: string = '';
  email: string = '';
  username: string = '';
}

And trying to use it this way

import User from '../models/User';

let user = new User(action.payload.session.user);

And getting

TypeError: Class constructor Record cannot be invoked without 'new' at new User

Nested dataclasses are either not supported or undocumented

I like your library, I'm thinking about how to implemented a nested Record

// I'm interested in something like this:
class Something extends Record<Something> {
  message: string
  timestamp: string
}

class User extends Record<User> {
  id: string
  something: Something
}

It is either undocumented or unsupported though.

`create` makes all properties optional

I'm not sure if this is a feature or a bug: when I create a new instance of a dataclass through .create all class attributes have been made optional.

Expected: attributes that are not explicitly marked as optional should be required so that the create method can raise a type error if a required property is missing.

class User extends Data {
  name: string;
  age: number;
}

// None of these raise type errors but should:
const user1 = User.create()
const user2 = User.create({ name: 'Ann' })

class UserWithOpt extends Data {
  name: string;
  age?: number;
}

// This would be OK:
const user3 = UserWithOpt.create({ name: 'Ann' })

Support for embedded class or object

It seems that this lib currently doesn't support embedded dataclass or JS object inside the dataclass. Try to add the following to the test.

  class Embedded extends Record {
    name: string = 'name';
    age: number = 1;
    entity: Entity;
    date: Date;
  }
  it.only('should compare dataclass with embedded class', () => {
    let embeddedA = new Embedded({
      entity: new Entity(),
      date: new Date('1996-12-17T03:24:00')
    })
    let embeddedB = new Embedded({
      entity: new Entity({ someString: 'sadasd' }),
      date: new Date('1995-12-17T03:24:00')
    })
    console.log(embeddedA.toJSON())
    console.log(embeddedA.entity)
    expect(embeddedA.equals(embeddedB)).toBe(false);
  })

I suppose embeddedA.toJSON() should also print the entity and date and equals should be false when comparing embeddedA and embeddedB. Is it possible to add this feature?
It seems that currently we can only define primitive type inside the dataclass which is a big limitation for the lib to be useful....

Is it possible to define compulsory fields (without defaults)?

I want to define a simple Record in which all fields are compulsory. This code complies fine:

import Record from 'dataclass'

class Location extends Record<Location> {
    name: string = '';
    address: string = '';
}

But what I'd really like to do is this:

import Record from 'dataclass'

class Location extends Record<Location> {
    name: string;
    address: string;
}

Where I don't provide a default value to my compulsory fields. Can this be done?

How to use function return value as a field efault value

Hi,

in Python the dataclass type supports calling a factory function to retrieve the default value for a field. For more information you can see here. The parameter is named default_factory for the Field descriptor class which is used to declare extra information for each field.

Is it possible to achieve the same functionality with this package?

TypeError: Class constructor Data cannot be invoked without 'new'

Hello,

I tried to run the example and got this error:

/home/zeus/Documents/sauvvi/sauvvi-calendar-site/tests/dataclass.test.js:23
        var _this = _super !== null && _super.apply(this, arguments) || this;
                                              ^

TypeError: Class constructor Data cannot be invoked without 'new'
    at new User (/home/zeus/Documents/sauvvi/sauvvi-calendar-site/tests/dataclass.test.js:23:47)
    at Function.create (/home/zeus/Documents/sauvvi/sauvvi-calendar-site/node_modules/dataclass/dataclass.js:12:36)
    at Object.<anonymous> (/home/zeus/Documents/sauvvi/sauvvi-calendar-site/tests/dataclass.test.js:31:17)
    at Module._compile (node:internal/modules/cjs/loader:1218:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1272:10)
    at Module.load (node:internal/modules/cjs/loader:1081:32)
    at Module._load (node:internal/modules/cjs/loader:922:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:23:47

Node.js v18.13.0

The code:

import { Data } from "dataclass";

// 1. easily describe your data classes using just language features
class User extends Data {
  name: string = "Anon";
  age: number = 0;
}

// 2. instantiate classes while type systems ensure correctness
let user = User.create({ name: "Liza", age: 23 });
// > User { name: "Liza", age: 23 }

// 3. make changes while benefiting from immutable values
let updated = user.copy({ name: "Ann" });
// > User { name: "Ann", age: 23 }
updated = updated.copy({ name: "Liza" });
// > User { name: "Liza", age: 23 }

// 4. compare objects by their value, not reference
console.log(user === updated, user.equals(updated));
// > false, true

Typescript dont allow me to use new with the .create.

This is my tsconfig.json:

{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types", "./typings"],
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "strictPropertyInitialization": false,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": false,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

copy() method makes plain Object (TypeScript)

Hi. Thanks for the great lib, just what I was looking for.
I have found that copy() produces just a plain JS object and I lose all extra methods and features.
But it works as expected if I change the copy() method in the dataclass this way::
- return new this.constructor(custom);
+ return new (Object.getPrototypeOf(this)).constructor(custom);
Not sure though if it is applicable for all cases.
Gist for tests

Attemp to instantiate a class raises "TypeError: Cannot redefine property" on NodeJS 14.17.6

First of all, thank you for a great package!

I wonder whether it's a misconfiguration issue, but for me the README code raises the aforementioned error:

import Record from "dataclass";

class User extends Record {
  name = 'Anonymous';
}

let user = new User({ name: 'Liza' });

Eg when executed as a standalone file, along with the following package.json:

{
  "type": "module",
  "dependencies": {
    "dataclass": "^1.2.0"
  }
}

The same error is happening in Firefox.

Object prototype undefinded

No matter what I do, including the exact few lines of TypeScript example for User, I get the following error when the program runs, either through ts-node or compile JS code:

> [eval]:7
        return extendStatics(d, b);
               ^
TypeError: Object prototype may only be an Object or null: undefined
    at setPrototypeOf (<anonymous>)

TS 3.5.2
node 8.9.3 & 11.12.0

Dataclass doesn't work in Jupyter notebook

Hi,

First of all, thank you for your time and effort into making this project. I really appreciate that I'm able to stand on the shoulders of giants.

I'm trying to use Dataclass in a Jupyter/tslab notebook, but it fails:

import { Data } from "dataclass";

class Foo extends Data {
    name: string
    value: number
}

let a = Foo.create({name: "test", value: 42})

This gives the following output:

/private/tmp/jupyter-ts/node_modules/dataclass/dataclass.js:8
  O.freeze(O.assign(O.seal(O.assign(O.create(proto), base)), values));
             ^

TypeError: Cannot add property name, object is not extensible
    at Function.assign (<anonymous>)
    at produce (/private/tmp/jupyter-ts/node_modules/dataclass/dataclass.js:8:14)
    at Foo.create (/private/tmp/jupyter-ts/node_modules/dataclass/dataclass.js:12:12)
    at evalmachine.<anonymous>:8:13
    at evalmachine.<anonymous>:11:3
    at sigintHandlersWrap (node:vm:270:12)
    at Script.runInThisContext (node:vm:127:14)
    at Object.runInThisContext (node:vm:307:38)
    at Object.execute (/private/tmp/jupyter-ts/node_modules/tslab/dist/executor.js:162:38)
    at JupyterHandlerImpl.handleExecuteImpl (/private/tmp/jupyter-ts/node_modules/tslab/dist/jupyter.js:219:38)

I don't think this is an issue with dataclass itself, but I this seems like the most logical place to start. Feel free to point me to a better place to get help.

Regards,

Value validation

Hi everyone, I'm trying to figure out how to implement a method to add custom validation.

Some idea?
Thanks a lot!

Document parameter properties as a partial alternative

Parameter properties reduce some of the boilerplate associated with TypeScript classes.

They can be used to change:

class Octopus {
  private legs;
  private numberOfLegs;
  constructor(name: string, numberOfLegs: number) {
    this.name = name;
    this.numberOfLegs = numberOfLegs;
  }
}

To:

class Octopus {
  constructor(private name: string, private numberOfLegs: number) {}
}

Which partially addresses some of the boilerplate issues related to TypeScript classes.

Create data class without default values

Hi, Alexey! Thank you for great lib!

Is there possible to create data class without default values?

Now if try that:

class User extends Data {
  name: string;
  age: number;  
}

const user = User.create({ name: "Evlampy", age: 20 });

Then got:

Uncaught (in promise) TypeError: Cannot add property name, object is not extensible

I know it's possible to define class with null values, but it's not same.
The goal is don't define default values in class and prevent instantiating with empty values.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.