Typescipt泛型-返回具有相同类型的泛型参数的新实例

时间:2020-06-30 08:43:56

标签: typescript generics

让我们说我有两个从某个接口继承的类:(为简单起见,将其简化)

interface IVehicle {}

class Car implements IVehicle { 
    constructor(public color: string) {} 
}
class Helicopter implements IVehicle {}

我现在有了一个给定实例(类型扩展为IVehicle)的函数,该函数将返回相同类型的新实例

function clone<T extends IVehicle>(element: T): T {
    if (element instanceof Car) {
        return new Car(element.color);
    }
    ...
    return element;
}

clone(new Helicopter())

但是我在return new Car(...)周围看到一条错误消息:

'Car' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'IVehicle'

哪个似乎不正确,因为instanceof应该证明T是子类型Car正确吗?

之后,我尝试使用T将返回类型转换为类型return new Car(element.color) as T;

但这现在会产生此错误:

Conversion of type 'Car' to type 'T' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

并包含第一个错误。

TypeScript是否遇到了合法的类型问题,或者这是错误?我是否缺少类型约束中的某些内容?如何解决此错误?

1 个答案:

答案 0 :(得分:1)

如果您打算克隆IVehicle实例,我认为将此操作添加到接口本身是一个很好的解决方案。

interface IVehicle<ActualType> {
    clone(): ActualType;
}

class Car implements IVehicle<Car> { 
    constructor(public color: string) {} 
    clone(): Car {
        return new Car(this.color);
    }
}

class Helicopter implements IVehicle<Helicopter> {
    clone(): Helicopter {
        return new Helicopter();
    }
}

const h = new Helicopter();
const hClone = h.clone();

更新

如果您不能修改Vehicles的来源,并且子类形成一个封闭的集合,则可以使用方法重载

interface IVehicle {}

class Car implements IVehicle { 
    constructor(public color: string) {} 
}

class Helicopter implements IVehicle {}

function clone(element: Car): Car;
function clone(element: Helicopter): Helicopter;
function clone(element: IVehicle): IVehicle {
    if (element instanceof Car) {
        return new Car(element.color);
    } else if (element instanceof Helicopter) {
        return new Helicopter();
    } else {
        throw new Error("Unknown subclass of IVehicle passed to clone " + element)
    }  
}

const h = new Helicopter();
const h1 = clone(h);