将类作为参数传递会导致"不可更新"错误

zw0*_*0rk 54 typescript

我试图将一个类作为参数传递给某个函数,它将实例化该类并返回它.这是我的代码:

module A.Views {
  export class View { ... }
}

module A.App {
  export class MyApp {
    ...
    registerView(viewKlass:A.Views.View):void
    {
        var test = new viewKlass;
    } 
  }
}
Run Code Online (Sandbox Code Playgroud)

当我试图编译这个时,我得到:

(...): Value of type 'Views.View' is not newable.
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

如果newable类型值是对象构造函数,我如何在运行时传递构造函数?

小智 74

我们需要说一些typeof(MyClass)来区分对象和函数签名中的类.

无论如何,您实际上可以通过使用构造函数类型签名来解决您的问题.考虑这个课程:

class MyClass {
    constructor (private name: string) {
    }
}
Run Code Online (Sandbox Code Playgroud)

要将该类作为可以在函数中实例化的类型传递,实际上必须复制类构造函数签名,如下所示:

function sample(MyClass: new (name: string) => MyClass) {
    var obj = new MyClass("hello");
}
Run Code Online (Sandbox Code Playgroud)

编辑: 在codeplex上找到一个简单的解决方案:

您必须为您的类创建一个接口,如下所示:

interface IMyClass {
    new (name: string): MyClass;
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的函数签名中使用它:

function sample(MyClass: IMyClass) {
    var obj = new MyClass("hello");
}
Run Code Online (Sandbox Code Playgroud)

  • 函数样本(MyClass:typeof MyClass)应该这样做. (71认同)
  • 如果你不知道构造函数参数,你也可以在你的界面中使用`new(... args:any []):MyClass`. (2认同)
  • 实际上,Corey 注释中的“function example(MyClass: typeof MyClass)”只能**仅**适用于非抽象类。要对[抽象类](https://www.typescriptlang.org/docs/handbook/classes.html#abstract-classes)做同样的事情,`function example(MyClass: new (name: string) => MyClass) ` 是一个更好的选择。 (2认同)

Mat*_*vis 22

试试这个:

export class MyApp {
    registerView(viewKlass: typeof A.Views.View): void {
        var test = new viewKlass();
    } 
}
Run Code Online (Sandbox Code Playgroud)


Mei*_*hes 13

补充其他答案; 我有一个实用程序类型,以保证通用参数/字段是类/ newable:

/* new T() */
export type Newable<T> = { new (...args: any[]): T; };
Run Code Online (Sandbox Code Playgroud)

然后,您可以确保获得类构造函数:

class MyApp<TViewBase>
{
  register<TView extends TViewBase>(view: Newable<TView>) { 
  }
}
Run Code Online (Sandbox Code Playgroud)

Newable<T>方法的工作原理,其中typeof T--where T是一个通用的类型-不.

例如: register<T extends TViewBase>(view: typeof T)导致以下错误:

[ts]'T'仅指类型,但在此处用作值.

  • 这是一个很好的答案,你能解释一下它是如何工作的吗? (2认同)
  • 这应该是公认的答案,老实说,包含在 TypeScript 中。这绝对优于试图识别类的构造函数的确切签名。 (2认同)

Ste*_*aul 11

在TypeScript中有两种传递类的方法.如果你:

  • 知道你正在经历的班级的超类(已经由Corey Alix推荐):

    class MyClass extends MySuperClass{ }
    
    makeMyClass(classRef: typeof MySuperclass) {
        return new classRef();
    }
    
    makeMyClass(MyClass);
    
    Run Code Online (Sandbox Code Playgroud)
  • 知道类的构造函数的签名:

    class MyClass {
        constructor(arg: string) {}
    }
    
    makeMyClass(classRef: { new(arg: string) }) {
        return new classRef('hello');
    }
    
    makeMyClass(MyClass);
    
    Run Code Online (Sandbox Code Playgroud)

  • 如果MySuperclass是一个抽象类怎么办?我不能使用typeof MySuperclass,因为它不可能在抽象类上调用构造函数. (4认同)

ya_*_*mon 7

如果你使用 Angular,他们已经实现了 Type,它类似于Meirion Hughes 的回答

import {Type} from '@angular/core';

export class MyApp {
  ...
  registerView(viewKlass: Type<A.Views.View>):void
  {
      var test = new viewKlass();
  } 
}
Run Code Online (Sandbox Code Playgroud)

  • 出于相同的目的,在“@nestjs/common”中也实现了类似的东西。 (2认同)