82

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

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

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

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

(...): Value of type 'Views.View' is not newable.

我究竟做错了什么?

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

4

8 回答 8

109

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

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

class MyClass {
    constructor (private name: string) {
    }
}

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

function sample(MyClass: new (name: string) => MyClass) {
    var obj = new MyClass("hello");
}

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

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

interface IMyClass {
    new (name: string): MyClass;
}

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

function sample(MyClass: IMyClass) {
    var obj = new MyClass("hello");
}
于 2012-10-13T08:45:30.373 回答
32

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

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

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

class MyApp<TViewBase>
{
  register<TView extends TViewBase>(view: Newable<TView>) { 
  }
}

Newable<T>方法适用于typeof T--whereT是泛型类型 -- 不适用的地方。

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

[ts] 'T' 仅指一种类型,但在这里用作值。

于 2017-08-31T14:06:36.000 回答
31

试试这个:

export class MyApp {
    registerView(viewKlass: typeof A.Views.View): void {
        var test = new viewKlass();
    } 
}
于 2016-06-28T16:18:59.487 回答
21

在 TypeScript 中传递类有 2 种方法。如果你:

  • 知道您正在通过的类的超类(Corey Alix 已经推荐):

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

    class MyClass {
        constructor(arg: string) {}
    }
    
    makeMyClass(classRef: { new(arg: string) }) {
        return new classRef('hello');
    }
    
    makeMyClass(MyClass);
    
于 2017-04-25T14:24:38.883 回答
10

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

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

export class MyApp {
  ...
  registerView(viewKlass: Type<A.Views.View>):void
  {
      var test = new viewKlass();
  } 
}
于 2019-10-09T16:00:28.203 回答
3

我知道这是一个老问题,但这里有:

...
registerView(viewKlass: { new(): A.Views.View }):void
{
    var test = new viewKlass();
} 

在这里找到了答案。

于 2017-07-02T18:06:18.227 回答
3

根据您的情况,以下三种解决方案可能还不够:

  1. myClass: new (name: string) => MyClass
  2. interface IMyClass { new (name: string): MyClass; }; myClass: IMyClass
  3. myClass: typeof MyClass

在某些情况下,您想调用一些静态方法,例如myClass.someMethod(). 1并且2不允许您这样做(并且请不要在您的应用程序中使用任何),因为他们不知道该方法。

或者在某些情况下,您希望将其MyClass作为抽象类并使用let instance = new myClass. 那样的话,3就会失败。

在这些情况下,我所做的是创建一个特殊的类型来MyClass解决我上面强调的问题,它看起来像这样:

type MyClassContructor<T extends MyClass> = typeof MyClass & Constructor<T>;

顺便提一句。不要忘记将返回类型添加到您的方法中,以便获得正确的智能感知。

于 2019-10-04T15:36:12.577 回答
-1

感谢您的要点 - 稍作改动即可使一切正常。在下面的示例中,我们在具体测试视图中“新建”TestView以传递,而不是尝试在方法中新建它。

module V.Views {
   export class View {
      public someVar: any;
      // the presence of constructor doesn't affect the error triggering
   }
}

module V.App {
    export class Application {
        public registerView(url: string, viewKlass: V.Views.View): void
        {
            var test = viewKlass;
        }
    }
}

var app = new V.App.Application;

class TestView extends V.Views.View {
}

class TestView2 extends V.Views.View {
}

app.registerView('', new TestView())
app.registerView('content/view/:slug/', new TestView2())
于 2012-10-09T15:09:25.670 回答