Typescript: How to set method return value => subclass
You can have this
as a return type and you can access the constructor of your current object with this.constructor
. That allows you to work more easily with subclassed immutables.
abstract class Point {
public readonly x: number;
public readonly y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
diff(point: Point): this {
return this.update(this.x - point.x, this.y - point.y);
}
// many methods like diff(); and then...
protected abstract update(x: number, y: number): this;
}
class ImmutablePoint extends Point {
protected update(x: number, y: number): this {
return new (<any>this.constructor)(x, y);
}
}
class MutablePoint extends Point {
public x: number;
public y: number;
protected update(x: number, y: number): this {
this.x = x;
this.y = y;
return this;
}
}
const pointA: ImmutablePoint = new ImmutablePoint(10, 10)
const pointB: ImmutablePoint = new ImmutablePoint(6, 2);
const result: ImmutablePoint = pointA.diff(pointB);
You can make Point
generic:
abstract class Point<T extends Point<any>> {
public readonly x: number;
public readonly y: number;
constructor(x: number, y: number) {
...
}
diff(point: Point<any>): T {
return this.update(this.x - point.x, this.y - point.y);
}
protected abstract update(x: number, y: number): T;
}
class ImmutablePoint extends Point<ImmutablePoint> {
protected update(x: number, y: number): ImmutablePoint {
return new ImmutablePoint(x, y);
}
}
class MutablePoint extends Point<MutablePoint> {
public x: number;
public y: number;
protected update(x: number, y: number): MutablePoint {
...
return this;
}
}
const pointA: ImmutablePoint = new ImmutablePoint(10, 10)
const pointB: ImmutablePoint = new ImmutablePoint(6, 2);
const result: ImmutablePoint = pointA.diff(pointB); // fine
(code in playground)
With the new Default generic type variables feature available you should be able to do something like:
abstract class Point<T extends Point = Point> {
...
}
(haven't tested it yet)