打字稿:如何设置方法返回值=>子类

时间:2017-03-09 21:07:01

标签: typescript

我有一个包含两个子类的父类:

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): Point {
        return this.update(this.x - point.x, this.y - point.y);
    }
    // many methods like diff(); and then...

    protected abstract update(x: number, y: number): Point;
}



class ImmutablePoint extends Point {
    protected update(x: number, y: number): Point {
        return new ImmutablePoint(x, y);
    }
}



class MutablePoint extends Point {
    public x: number;
    public y: number;

    protected update(x: number, y: number): Point {
        this.x = x;
        this.y = y;
        return this;
    }
}


const pointA: ImmutablePoint = new ImmutablePoint(10, 10)
const pointB: ImmutablePoint = new ImmutablePoint(6, 2);

但是diff()方法返回一个Point,而不是一个ImmutablePoint

// Error: type 'Point' is not assignable to parameter of type 'ImmutablePoint'.
const result: ImmutablePoint = pointA.diff(pointB);

我正在寻找一种在不编写新实现的情况下在子类上重新定义方法签名的方法,是否可能?

我还尝试使diff()返回值this,但它不起作用,因为ImmutablePoint不返回this而是返回一个新的ImmutablePoint

Playground Link

2 个答案:

答案 0 :(得分:5)

您可以Point通用:

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

使用新的Default generic type variables功能,您应该可以执行以下操作:

abstract class Point<T extends Point = Point> {
  ...
}

(尚未测试过)

答案 1 :(得分:2)

您可以将this作为返回类型,并可以使用this.constructor访问当前对象的构造函数。这样,您就可以更轻松地处理子类不可变对象。

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);