microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.92k stars 12.47k forks source link

Handle breaking change in class property runtime behavior #27644

Closed RyanCavanaugh closed 5 years ago

RyanCavanaugh commented 6 years ago

From https://github.com/Microsoft/TypeScript/issues/12212#issuecomment-428342448 @joeywatts:

class A {
    property = 'some string';
}
class B extends A {
    property;
}
const instanceB = new B();
// "some string" or "undefined" ?
console.log(instanceB.property);

It appears from the current definition at https://github.com/tc39/proposal-class-fields that this code will print undefined.

If the proposal advances further with these semantics, we'll need to figure out a mitigation strategy, preferably sooner rather than later.

One option is to make the code as written a type error for ~2 versions and force people to write an explicit = undefined initializer, then remove the error.

Edit [@sandersn]:

Here is the current plan, together with what has happened so far.

TypeScript 3.6

TypeScript 3.7

TypeScript 3.8

(or, the first version after class fields reaches Stage 4)

shrinktofit commented 5 years ago

What about decorators? Will the property descriptor is passed to decorator if useDefineForClassFields: true?

sandersn commented 5 years ago

@trotyl @mbrowne The corpus I inspected, our internal test repos + the ones at ~/Typescript/tests/cases/user, shows that people rarely override properties with accessors and vice versa. I tested the code with --useDefineForClassFields, which disallows property/accessor and access/property overrides.

In fact, failures only happened in older code: there was one example of a property-override-accessor in Angular 2's examples. I believe it was intentional, and would only work with [[Set]]. There were 7 examples of accessor-override-property, all of which were trying to make the derived property readonly by only providing get, which would crash with [[Set]], so I think those accessors were never used.

For modern TS, they would instead write

class B {
  x = 1
}
class D extends B {
  readonly x = 2
}

Google and Bloomberg also checked their code bases and found no tricky failures. It's safe to conclude that [[Set]] vs [[Define]] is not practically important.

sandersn commented 5 years ago

Since this targets 3.7.1, I'm going to close this bug. When class fields reaches stage 4, I'll do the final two steps.