In the context of TypeScript, attempting to directly cast a Parent
instance to a Child
can be problematic. The compiler lacks enough information to confirm that the Parent
instance is indeed an instance of Child
. To address this issue, it is recommended to utilize type guards instead of explicit casting:
class Parent {
prop: string|null = null;
isChild(): this is Child {
return (this as any).otherProp !== undefined;
}
}
class Child extends Parent {
otherProp: string|null = null;
}
function test(p: Parent) {
if (p.isChild()) {
console.log(p.otherProp);
}
}
By utilizing a type guard like in the example above, within the guarded conditional statement, TypeScript recognizes p
as a Child
, while outside of it, p
remains treated as a Parent
.
An alternative approach involves overriding the type guard in the subclass, eliminating the need for explicit typecasting entirely:
class Parent {
prop: string|null = null;
isChild(): this is Child {
return false;
}
}
class Child extends Parent {
otherProp: string|null = null;
isChild(): this is Child {
return true;
}
}
function test(p: Parent) {
if (p.isChild()) {
console.log(p.otherProp);
}
}
The reasoning behind this behavior by TypeScript developers regarding whether it's intentional or accidental remains unconfirmed. It may serve as a safety measure to detect potential errors, but concrete documentation on this specific behavior is unavailable.
If you prefer a cleaner syntax, explicitly define the type of this
in the castToChild
method to streamline the process of converting to a Child
:
class Parent {
prop: string|null = null;
castToChild(this: Parent): Child {
return this as Child;
}
}
class Child extends Parent {
otherProp: string|null = null;
}
function foo() {
let p: Parent = new Child();
let c = p.castToChild();
console.log(c.otherProp);
}
This modification essentially performs a double cast operation, albeit with a cleaner appearance. Nevertheless, it highlights the quirks in behavior wherein without specifying the this
parameter, this
defaults to Parent
and becomes non-castable, whereas with the specified parameter, the casting operation succeeds.