【问题标题】:Typescript: How to set method return value => subclass打字稿:如何设置方法返回值=>子类
【发布时间】:2020-08-11 21:38:13
【问题描述】:

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

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

【问题讨论】:

  • 为什么要记下result 类型为Point?代码改为“接口”。
  • 是的,事实上你可以在任何地方使用超类而不是子类作为类型,但是我们有 ImmutablePoints 的原因主要是用作(不可变)参数,并且必须在每个时间。很烦人。实际上只是看到我粘贴的错误说“类型参数”:P

标签: typescript


【解决方案1】:

您可以将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);

【讨论】:

  • 我不知道this能给我一个新实例
  • 哎呀,我修复了丢失的“新”。抱歉迟到了
【解决方案2】:

您可以将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> {
  ...
}

(还没有测试过)

【讨论】:

    猜你喜欢
    • 2018-04-26
    • 1970-01-01
    • 2020-01-10
    • 2019-12-06
    • 1970-01-01
    • 2019-09-08
    • 2018-07-01
    • 2020-10-13
    • 2021-05-16
    相关资源
    最近更新 更多