alexeyraspopov / dataclass

Data classes for TypeScript & JavaScript
https://dataclass.js.org
ISC License
181 stars 6 forks source link

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

Closed teixeirazeus closed 1 year ago

teixeirazeus commented 1 year ago

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"
  ]
}
nlhnt commented 1 year ago

Same error, just decided to define my classes in a poc_dataclass.ts file, compiled it into a poc_dataclass.js file, imported my dataclass and was met with the same error.

I'm mainly a python developer, but decided to focus on nodejs / deno for my side projects... This is not yet production ready in my opinion, but it is a great idea and I'm hoping this project will explode. Dataclasses are great :)

alexeyraspopov commented 1 year ago

@teixeirazeus,

Looking at the tsconfig.json, you're trying to compile your code to ES5, which doesn't have classes yet. The Data parent class is being shipped as ES6 (ES2015) class, which doesn't allow calling it as a function. When TypeScript compiles a class to an ES5 constructor function, and the class uses inheritance, TS needs to call parent constructor, which is being done via ParentClass.call(this). This is where ES6 class throws an error (since Data is still an ES6 class, while your usage code transpiled to ES5's constructor functions).

Looking at module: esnext, maybe you don't need to compile your code to ES5, but stick to at least ES6 (ES2015)? It may not be an option if you need to support old browsers like Internet Explorer 11 though. If switching to at least ES2015 is not an option, another way of fixing this behavior is making sure your setup also does transform dependencies to ES5. @nlhnt, if that's just a side project, I bet you'd have better time not compiling code to very old spec.

There were historical reason to abandon shipping ES5 version of dataclass. Dealing with all sorts different setups and spec incompatibilities is nightmare. I know it may not be the answer you're looking for, I'm sorry.

teixeirazeus commented 1 year ago

Thanks for replying :)