Closed
Description
TypeScript Version: 2.8.3
Search Terms: generic this, override, polymorphic this
Code
namespace N1 {
/*
The following method override generates:
Property 'f' in type 'D' is not assignable to the same property in base type 'C'.
Type '<T extends D>(this: T, arg: keyof T) => void' is not assignable to type '<T extends C>(this: T, arg: keyof T) => void'.
The 'this' types of each signature are incompatible.
Type 'T' is not assignable to type 'D'.
Type 'C' is not assignable to type 'D'.
Property 'y' is missing in type 'C'.
Why is generic T treated differently to polymorphic this?
*/
class C {
x: number;
f<T extends C>(this: T, arg: keyof T) { }
}
class D extends C {
y: string;
f<T extends D>(this: T, arg: keyof T) { }
}
}
namespace N2 {
/*
By adding a pointless overload the method override works fine.
*/
class C {
x: number;
f<T extends C>(this: T, arg: keyof T): void;
f<T extends C>(this: T, arg: keyof T): void;
f<T extends C>(this: T, arg: keyof T) { }
}
class D extends C {
y: string;
f<T extends D>(this: T, arg: keyof T) { }
}
}
namespace N3 {
/*
The problem occurs similarly with static methods where polymorphic this is
not available. This time the error occurs on the definition of D however.
As before, overloading works around the issue.
*/
type Constructor<T> = { new(...args: any[]): T };
class C {
x: number;
static c: boolean;
// static f<T extends C>(this: Constructor<T>, arg: keyof T): void;
// static f<T extends C>(this: Constructor<T>, arg: keyof T): void;
static f<T extends C>(this: Constructor<T>, arg: keyof T) { }
}
class D extends C {
y: string;
static d: boolean;
static f<T extends D>(this: Constructor<T>, arg: keyof T) { }
}
}
namespace N4 {
/*
This is another workaround using T extends C in the sub-class but still contraining this
to be a D class or subclass.
*/
type Constructor<T> = { new(...args: any[]): T };
class C {
x: number;
static c: boolean;
static f<T extends C>(this: typeof C & Constructor<T>, arg: keyof T) { }
}
class D extends C {
y: string;
static d: boolean;
static f<T extends C>(this: typeof D & Constructor<T & D>, arg: keyof T) { }
}
}
Expected behavior:
Non-static case: behavior should be the same, with and without use of overloading. It seems as if the overloaded behavior is correct. T
should be treated as if it were polymorphic this.
Static case: this is more of a problem because this pattern seems to be the current best practice for achieving static polymorphic this (see: [#5863]). Both of the workarounds ought not be needed.