This is something I\'ve been doing in older versions of TypeScript and I use this method in C#, but it doesn\'t work in the latest 1.0 version of TypeScript.
Here\'s
I accepted Steve's answer because he suggested to use Base<T extends Base<any>>
, but I wanted to keep a copy of the code change that fixed the problem on Stack Overflow:
class Base<T extends Base<any>> { // 1. Set as any
children: Array<T>;
doAction() {
this.children[0].promise();
}
promise(): T {
return <any> this; // 2. cast to any
}
}
class Child extends Base<Child> {
public myString: string;
}
new Child().promise().myString;
This requires a cast to any, but it's not so bad since it's only in the base class. This change doesn't affect anything using the Child or Base classes, so overall it was a very ideal alternative.
Update: In TS 1.7+ this can be done using a polymorphic this:
class Base {
children: Array<this>;
doAction() {
this.children[0].promise();
}
promise(): this {
return this;
}
}
class Child extends Base {
public myString: string;
}
new Child().promise().myString;
You are no longer allowed to use T
here:
class Base<T extends Base<T>>
--------------------------^
You either have to make your class non-generic or use:
class Base<T extends Base<any>>
The reason given for this was to make the compiler simpler:
In our continued efforts to simplify the language, we're simplifying what generic constraints can entail.
The added overhead in terms of type-checking, error-reporting, and design complexity did not add enough additional expressiveness to make it worthwhile for 1.0. We may revisit this in future versions of TypeScript.
-- Breaking Changes Wiki
promise() : T { return this; }
it is very weak assumption that can be easily broken, because downcasting defined in a base class just cannot work for any sub-class
For example in you case, if anyone defines class SuperChild extends Child {}
then promise()
of SuperChild
is going to give you Child
instead of SuperChild
.
Besides that here is how you can make it work the way it used to:
class Base<T> {
public children : Array<T>;
constructor(
private toSelf: () => T,
private toBase: (something: T) => Base<T>
) {
}
doAction() {
this.toBase(this.children[0]).promise(); // used to work
}
promise() : T {
return this.toSelf(); //
}
}
class Child extends Base<Child> {
public myString: string;
}
function toThis() { return this; }
new Child(toThis, x => x).promise().myString; // used to work