【问题标题】:Overload class type definition in Typescript在 Typescript 中重载类类型定义
【发布时间】:2020-10-06 23:40:50
【问题描述】:

我想在 TypeScript 中重载一个类定义,这样当该类被实例化时使用一个传递给构造函数的值,某个属性由提供的类型变量键入(比如number )。当类实例化没有传递给构造函数的值时,相同的属性被键入为:提供的类型变量未定义(即number | undefined)。

一个例子:

const car1 = new Car<number>(1);
car1.maxSpeed                 // maxSpeed is of type number

const car2 = new Car<number>();
car1.maxSpeed                 // maxSpeed is of type number | undefined

如何做到这一点?

【问题讨论】:

  • 我更新了答案,也许有帮助?

标签: typescript typescript-typings


【解决方案1】:

您当然可以描述声明一个以这种方式工作的类构造函数:

interface CarConstructor {
    new <T>(): Car<T | undefined>;
    new <T>(maxSpeed: T): Car<T>;
}
interface Car<T> {
    maxSpeed: T
}

declare const Car: CarConstructor;

const car1 = new Car<number>(1);
car1.maxSpeed // maxSpeed is of type number

const car2 = new Car<number>();
car2.maxSpeed // maxSpeed is of type number | undefined

CarConstructor 有两个构造签名,按照您所说的方式重载。


问题在于实现这样的CarConstructor。 TypeScript 不允许您将类型参数放在 class 构造函数上,因为目前编译器从类声明本身而不是从构造函数获取任何泛型类类型参数:

class BadCar<T> {
    maxSpeed: T;
    constructor<T>(): Car<T | undefined>; // error! no type params
    constructor<T>(maxSpeed: T): Car<T>; // error! no type params
    constructor(maxSpeed?: T) {
        this.maxSpeed = maxSpeed; // error! can't tell this is valid
    }
}

现在你所能做的就是创建一个“足够接近”的类,然后注释或assert 它是CarConstructor

const Car: CarConstructor = class <T> {
    maxSpeed: T;
    constructor(maxSpeed?: T) {
        this.maxSpeed = maxSpeed as T; // <-- assume undefined is in T 
    }
}

这可行,但它很麻烦,并且可能会变得更麻烦,因为Car 中存在的功能越多(你会发现自己到处都在做冗余的属性/方法定义)。


存在一个现有的 GitHub 问题,microsoft/TypeScript#35387,要求更容易直接实现具有此类重载构造函数的类。如果你真的需要这个,你可能想去那个问题,给它一个 ? 并描述为什么你的用例是引人注目的。


当然,最简单的事情就是不要与 TypeScript 对抗,而是使用不同的解决方案,比如工厂函数:

class DumbCar<T> {
    constructor(public maxSpeed: T) { }
}

function newCar<T>(x: T): Car<T>;
function newCar<T>(): Car<T | undefined>;
function newCar<T>(x?: T): Car<T | undefined> | Car<T> {
    return new DumbCar(x);
}

Playground link to code

【讨论】:

    【解决方案2】:

    通常不可能,如果您尝试注释构造函数,您会得到:

    类型注释不能出现在构造函数声明中。 ts(1093)

    在这种情况下,您可能应该只定义一个工厂函数。


    如果明确提供了类型,您可以直接指定它:

    class Car<T>
    {
        maxSpeed: T;
        // ...
    
        constructor();
        constructor(maxSpeed: T);
        constructor(maxSpeed?: any)
        {
            this.maxSpeed = maxSpeed;
        }
    }
    
    const car1 = new Car<number | undefined>();
    const car2 = new Car<number>(1);
    

    请注意,这需要strict null checks 编译器选项。

    【讨论】:

      猜你喜欢
      • 2018-03-14
      • 2021-04-11
      • 2021-01-31
      • 2017-12-21
      • 2019-04-01
      • 2021-03-26
      • 2021-05-17
      • 2017-08-23
      • 2017-02-28
      相关资源
      最近更新 更多