【问题标题】:Abstract constructor type in TypeScriptTypeScript 中的抽象构造函数类型
【发布时间】:2016-08-21 12:43:46
【问题描述】:

TypeScript 中非抽象类(非抽象构造函数)的类型签名如下:

declare type ConstructorFunction = new (...args: any[]) => any;

这也称为 newable 类型。但是,我需要 abstract 类(抽象构造函数)的类型签名。我知道它可以被定义为具有Function 类型,但这方式 太宽泛了。没有更精确的替代方案吗?


编辑:

为了澄清我的意思,下面的小sn-p演示了抽象构造函数和非抽象构造函数之间的区别:

declare type ConstructorFunction = new (...args: any[]) => any;

abstract class Utilities {
    ...
}

var UtilityClass: ConstructorFunction = Utilities; // Error.

类型 'typeof Utilities' 不可分配给类型 'new (...args: any[]) => any'。

不能将抽象构造函数类型分配给非抽象构造函数类型。

【问题讨论】:

  • 您能详细说明一下吗?也许提供更多代码?为什么在这种情况下抽象类和非抽象类之间存在差异? ctor 从不抽象。
  • @NitzanTomer 感谢您的帮助。我已将minimal reproducible example 编辑到问题中以演示问题。基本上,我需要传递一个类作为参数。 ConstructorFunction 类型适用于非抽象类,但不适用于抽象类。

标签: constructor typescript abstract-class


【解决方案1】:

从 TypeScript 4.2 开始,您可以使用 abstract constructor type:

abstract class Utilities {
    abstract doSomething(): void;
}

type ConstructorFunction = abstract new (...args: any[]) => any;
var UtilityClass: ConstructorFunction = Utilities; // ok!

【讨论】:

  • 这是最好的答案,imo。
【解决方案2】:

感谢@TehauCave 的回答,这是我的出发点,我可以找到一种方法来定义一个也关心参数类型的类型。

export type Constructor<T, TArgs extends any[] = any> = Function & {
    prototype: T,
    apply: (this: any, args: TArgs) => void
};

以上类型都可以使用

  • 不管参数类型:

    Constructor<YourAbstractClass>
    

  • 限制参数类型:

    Constructor<YourAbstractClass, [number, string, boolean]>
    

使用Constructor 类型,也可以推断给定构造函数的参数类型:

type ConstructorParameters<T extends Constructor<any>> = T extends Constructor<any, infer TParams> ? TParams : never;

然后,

ConstructorParameters<YourAbstractClass> // e.g., [number, string, boolean]

【讨论】:

    【解决方案3】:

    这个解决方案:

    type Constructor<T> = Function & { prototype: T }
    

    不允许您使用 new 关键字创建这种类型的实例。

    还有一个简单的解决方案:

    type Constructor = new (...args: any[]) => AbstractClass
    

    ((AbstractClass 是您的 AbstractClass 的名称))

    【讨论】:

    • 在这种情况下,AbstractClass 是什么?
    【解决方案4】:

    我自己只是在为类似的问题而苦苦挣扎,这似乎对我有用:

    type Constructor<T> = Function & { prototype: T }
    

    【讨论】:

    • 谢谢,这正是我们所需要的。 @cheez - 这描述了一个带有原型的函数 - 所以不是要求类型定义构造函数,而是定义它定义原型。这就是抽象类 - 没有构造函数,只有原型。
    • 您能否分享一个使用抽象构造函数创建类的示例。也许包括扩展课程?
    • @Knagis 能否请您详细说明这个答案。我真的很想能够使用它,但是上面显示的方式对我来说并不是一个足够完整的答案。
    【解决方案5】:

    遇到同样的问题。我想,抽象类构造函数签名的本质是其声明中new ( ... ) : Xthingy 的absense。这就是它可以显式声明的原因。

    但是。你可以这样做,它会编译。

    var UtilityClass: typeof Utilities  = Utilities;
    

    typeof Something 是引用构造函数类型的好方法,但是它不能扩展。

    在任何情况下你都可以这样做:

    var UtilityClass: ConstructorFunction = <any> Utilities;
    

    【讨论】:

      【解决方案6】:

      抽象类(一般在 OO 中)的全部意义在于您无法实例化它们,您需要一个具体的非抽象实现。

      我假设您希望对该抽象类有不同的实现,并希望能够接收其中一种实现(作为参数或类似的东西)。
      如果是这样,那么也许这可能会解决您的问题:

      declare type ConstructorFunction<T extends Utilities> = new (...args: any[]) => T;
      
      abstract class Utilities { }
      
      class MyUtilities extends Utilities { }
      
      var UtilityClass: ConstructorFunction<MyUtilities> = MyUtilities; 
      

      【讨论】:

      • 不幸的是,我需要传递一个抽象类作为参数,如果参数类型是anyFunction,这是可能的。但是,这些类型也允许传递抽象类以外的对象,因此我需要一个类型定义,尤其是抽象类。
      • @JohnWhite 为什么需要传递一个抽象类?这是一个奇怪的场景
      • 是的。它用于自定义序列化/反序列化引擎,可以使用装饰器注释属性。支持成员多态,因此可以为属性类型指定抽象类,然后将其传递到元数据结构中。运行时类型检查目前已经到位,但使用类型安全会明显更好。
      • @JohnWhite 如果我理解正确,那么您只需要该抽象类即可从中获取元数据。如果是这种情况,那么只需将其命名为any,因为我看不到拥有类类型的好处。除非我遗漏了什么,否则你可能应该更好地解释这个场景以获得真正的帮助。
      • 我知道这很旧,但我遇到了同样的问题,我使用多态性将某个类的子类存储在映射中,但由于父类无法实例化它们被标记为摘要。我希望构造函数参数的类型安全,因为规范仍在不断变化,但由于编译器错误而无法获得。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 2020-11-11
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 2023-03-04
      相关资源
      最近更新 更多