The concept of the polymorphic this
type, introduced in the microsoft/TypeScript#4910 pull request, represents an implicit generic type parameter that is restricted to the current type. To illustrate, you can view this
as similar to This
in the declaration of a class like
class Example<This extends Example<This>> {⋯}
In your case, the propertyB
property exists as a conditional type dependent on a generic type parameter. The TypeScript compiler cannot determine its specific value until it knows the type argument assigned to the type parameter. As a result, this property behaves like a somewhat enigmatic type. TypeScript struggles to assess what values can be assigned to it, leading to error prompts for attempts such as this.propertyA ? null : 'value'
.
Though it seems logical that the evaluation of this.propertyA
should influence the type of this
, TypeScript fails to capture this nuance. The open issue at microsoft/TypeScript#33912 challenges the lack of support in modeling function return types and faces complexities due to assumptions needed when aligning generic conditional types with conditional checks.
Addressing these concerns proves challenging, evident from scenarios where assignments between a generic conditional type like T extends U ? V : W
and its counterpart isU(t) ? v : w
are not inherently compatible. This discrepancy reflects a broader problem showcased by the example provided:
class Example {
public readonly propertyA: boolean;
private readonly propertyB: this['propertyA'] extends true ? null : 'value';
public constructor() {
this.propertyA = true;
this.propertyB = this.propertyA ? null : 'value';
}
propB() { return this.propertyB }
}
class Subclass extends Example {
public readonly propertyA: false = false;
}
new Subclass().propB().toUpperCase(); // RUNTIME ERROR
In this scenario, despite refining the type of propertyA
in Subclass
, runtime errors arise due to inconsistencies in assigning values to propertyB
. While a workaround involving type assertions to ensure safety exists, implementing complete type safety remains elusive to TypeScript analysis.
To eliminate compiler errors, a type assertion can validate the assignment's integrity:
this.propertyB = (this.propertyA ? null : 'value') as
this['propertyA'] extends true ? null : 'value'; // no error
This resolves the compile-time issues, but necessitates meticulous verification of safety considerations before executing the assertion.
For further exploration, refer to the playground link for visualizing the discussed code snippets.