New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TypeScript] Typescript plugin overwrites parent class properties when the child narrows that property's type #9105
Comments
Hey @arilotter! We really appreciate you taking the time to report an issue. The collaborators If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack |
This issue seems to be blocking a import { Record } from 'immutable';
const defaults = { legCount: 2 };
class Animal extends Record(defaults) {
legCount: number;
}
const cat = new Animal({ legCount: 4 });
console.log(cat.legCount);
// Expect: 4
// Actual: undefined We have the same babel config as the OP. I've tried configuring it explicitly with |
This is expected behavior with Babel, because Typescript does not conform to the class field proposal's behavior and Babel does. If a parent class is responsible for defining a type, you should not be re-declaring it on the child class, because that means you are explicitly taking responsibility for making sure the value is correct. You'd either need to do |
I've opened microsoft/TypeScript#28823 to raise awareness about this issue. It was marked as a duplicate of microsoft/TypeScript#12437. While I really appreciate that Babel is pretty much 100 % spec compliant, I also would like it to be able to process TypeScript files correctly. I don't have high hopes for TS fixing the issue upstream, so I think a solution in Babel-land would be in order. If the class TestClass {
// we shouldn't encourage folks to write code like this, but tsc ensures
// that constructor param fields are set before field initializers run
field = this.constructorParam;
constructor(private constructorParam: string) {}
}
let instance = new TestClass('hello');
assert.equal(instance.field, 'hello'); From So not matter how you order the two plugins, one or the other thing breaks. Ideas for possible solutions:
|
Thank you! Lets see what the TS team says. |
One solution worth noting that I used to migrate from tsc to babel is declaration merging: interface A {}
interface B {}
class Base {
prop: A | B | null = null;
}
class Sub1 extends Base {
prop!: A | null; // type narrowed
}
// using declaration merging
interface Sub2 {
prop: A | null; // type narrowed
}
class Sub2 extends Base {
}
console.log(new Sub1().prop); // tsc: null, babel: undefined
console.log(new Sub2().prop); // tsc: null, babel: null |
Thanks for @galdebert 's idea, I have done the same thing using Declaration Merging:
But if we use the declaration merging like this:
|
You can now use |
Bug Report
Current Behavior
When a class (B) extends another class (A) and includes a type definition to narrow the type of something specified in class A, it will set the narrowed property's value to undefined. This diverges from the TSC behavior.
The output from the below code under babel is
a, undefined
.Input Code
Expected behavior/code
The output from the code should be
a, b
.Babel Configuration (.babelrc, package.json, cli command)
.babelrc:
Environment
Possible Solution
It seems like babel is setting
value = undefined
in the class property - it needs to check if that value is defined in the parent before overwriting it.The text was updated successfully, but these errors were encountered: