Description
Suppose I want to make a class with tons of chainable methods, like setters. This works fine.
class Chainable {
public set1(arg) {
this.arg1 = arg;
return this;
}
public set2(arg) {
this.arg2 = arg;
return this;
}
public set3(arg) {
this.arg3 = arg;
return this;
}
}
This allows us to create and setup a new Chainable much more concisely than would otherwise be possible.
a = new Chainable().set1(foo).set2(bar).set3(baz);
// vs
a = new Chainable();
a.set1(foo);
a.set2(bar);
a.set3(baz);
The problem occurs when we want to extend our Chainable class and maintain the chainability of the function calls.
class SuperChainable extends Chainable {
public set4(arg) {
this.arg4 = arg;
return this;
}
public set5(arg) {
this.arg5 = arg;
return this;
}
public set6(arg) {
this.arg6 = arg;
return this;
}
}
a = new SuperChainable().set4(foo).set1(baz);
// this is fine, because set4 returns a SuperChainable
a = new SuperChainable().set1(baz).set4(foo);
// this breaks, because set1 is returning a Chainable, not SuperChainable
var a: SuperChainable;
a = new SuperChainable.set1(baz); // typeError, set1 returns a Chainable, not SuperChainable
There is a workaround, but it is verbose and boiler-platey:
class SuperChainable extends Chainable {
public set4(arg) {
this.arg4 = arg;
return this;
}
public set5(arg) {
this.arg5 = arg;
return this;
}
public set6(arg) {
this.arg6 = arg;
return this;
}
public set1(arg) {
super.set1(arg);
return this;
}
public set2(arg) {
super.set2(arg);
return this;
}
public set3(arg) {
super.set3(arg);
return this;
}
}
When set1 is called on a SuperChainable and returns this
, the this
really is a SuperChainable and not a Chainable. So it seems to me that the typescript compiler is in error in treating the return value as a Chainable. If this error were fixed, it would be much easier to create inherited objects that support method chaining.
(copied over from now-closed issue on codeplex: https://typescript.codeplex.com/workitem/2332)