Using Polymorphic "this" for static members workaround from https://github.com/Microsoft/TypeScript/issues/5863 no longer works with subclassing in TypeScript 2.4.
TypeScript Version: 2.4.2
Code
class Parent {
static create<T extends Parent>(this: { new (): T }): T {
return new this();
}
}
class Child extends Parent {
static create(): Child {
return super.create<Child>();
}
}
Expected behavior:
Should not have type errors, which was the behavior in 2.3.4.
Actual behavior:
test.ts(7,7): error TS2417: Class static side 'typeof Child' incorrectly extends base class static side 'typeof Parent'.
Types of property 'create' are incompatible.
Type '() => Child' is not assignable to type '<T extends Parent>(this: new () => T) => T'.
Type 'Child' is not assignable to type 'T'.
May be related to #16790 and/or https://github.com/Microsoft/TypeScript/issues/5863#issuecomment-311593566
Unfortunately this pattern has been incorrect but undetected. See https://github.com/Microsoft/TypeScript/issues/17509#issuecomment-318839759.
Why are you overriding the definition anyway?
In my use case, create has a boolean flag parameter that needs to have a different default value in the two implementations. I just elided that for this minimum repro case.
Gotcha - you can be more explicit about the type parameter and just use a type assertion to tell the type system that you know better in this case, but it isn't quite as safe I suppose.
class Parent {
static create<T extends Parent>(this: { new (): T }): T {
return new this();
}
}
class Child extends Parent {
static create<T extends Child>(this: { new(): T}): T {
return super.create() as T;
}
}
@DanielRosenwasser Thanks! That does work, until I add a property to the child class that doesn't exist on the parent:
class Parent {
static create<T extends Parent>(this: { new (): T }): T {
return new this();
}
}
class Child extends Parent {
childProperty: string;
static create<T extends Child>(this: { new (): T }): T {
return super.create() as T;
}
}
test.ts(7,7): error TS2417: Class static side 'typeof Child' incorrectly extends base class static side 'typeof Parent'.
Types of property 'create' are incompatible.
Type '<T extends Child>(this: new () => T) => T' is not assignable to type '<T extends Parent>(this: new () => T) => T'.
The 'this' types of each signature are incompatible.
Type 'new () => T' is not assignable to type 'new () => Child'.
Type 'T' is not assignable to type 'Child'.
Type 'Parent' is not assignable to type 'Child'.
Property 'childProperty' is missing in type 'Parent'.
Any ideas?
(Also, if this needs to be closed and moved to a Stack Overflow or something, just let me know.)
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
This works and also provides access to any static members.
type Constructor<T> = { new(): T };
class Parent {
a = 7;
static b = true;
static create<T extends Parent>(this: typeof Parent & Constructor<T>) {
return new this();
}
}
class Child extends Parent {
y = 42;
static z = 'foo';
static create<T extends Parent>(this: typeof Child & Constructor<T & Child>) {
this.z; (new this).y;
return super.create() as T;
}
}
See [#23960].
@zamb3zi I don't have my original use case any more, but that looks pretty good, thanks!