-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Description
Bug Report
useDefineForClassFields defaults to true when target is set to es2022 or esnext. This is breaking lots of projects that use decorators.
This was reported in #45584, but that issue was closed apparently because the title didn't include which versions of TypeScript set useDefineForClassFields and because the TypeScript playground doesn't exhibit this same behavior. I've included a reproduction for tsc here.
This behavior is not documented anywhere in the TypeScript docs that I can find.
🔎 Search Terms
useDefineForClassFields decorators
🕗 Version & Regression Information
Since 4.2.4? according to #45584
Present in 4.6.3 and 4.7.0-dev.20220422
⏯ Playground Link
This playground link does not demonstrate the problem, as it doesn't default useDefineForClassFields like tsc does. But if you set useDefineForClassFields to true you will see that that decorators could not work because the field is not an instance property that shadows the decorator defined prototype accessors.
Playground link with relevant code
This git repo reproduces the problem locally: https://github.com/justinfagnani/ts-decorators-bug
💻 Code
This does not work with target es2022:
const observe = (proto: Object, name: PropertyKey) => {
const key = Symbol();
Object.defineProperty(proto, name, {
get() {
return this[key];
},
set(v: unknown) {
this[key] = v;
this.onChange?.(name, v);
}
});
};
class A {
@observe
foo = 'abc';
onChange(name: string, v: unknown) {
console.log(`${name} changed to ${v}`);
}
}
const a = new A();
a.foo = 'x'🙁 Actual behavior
useDefineForClassFields defaults to true
🙂 Expected behavior
Option 1: useDefineForClassFields defaults to false like for other permutations of module and target until the new behavior is documented and users are notified with a prominent breaking change notice on the decorators documentation and the release notes.
Option 2: Use constructor initialization for decorated properties even if useDefineForClassFields is true. This will keep projects from breaking regardless of the config.
Option 3: Disallow both useDefineForClassFields: true and experimentalDecorators in the same config.
This behavior is breaking a large number of our users. Sometimes they are in control of their own tsconfig and can set useDefineForClassFields to false, but sometimes the config is generated for them via some other tool and they don't know how to set the value. In this case their project is just broken and they blame our library, not the update to TypeScript that included the undocumented breaking change.