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

时间:2012-10-09 14:30:12

标签: typescript

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

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.

我做错了什么?

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

8 个答案:

答案 0 :(得分:66)

我们需要说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");
}

答案 1 :(得分:17)

试试这个:

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

答案 2 :(得分:9)

有两种方法可以在TypeScript中传递类。如果你:

  • 了解您正在通过的课程的超类(已由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);
    

答案 3 :(得分:9)

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

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

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

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

Newable<T>方法适用于typeof T - 其中T是通用类型 - 不是。

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

  
    

[ts]&#39; T&#39;仅指类型,但在此处用作值。

  

答案 4 :(得分:3)

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

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

找到了答案here

答案 5 :(得分:0)

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

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

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

或者在某些情况下,您想将MyClass作为抽象类,并使用let instance = new myClass创建myClass的实例。在这种情况下,3将失败。

在这些情况下,我要做的是为MyClass创建一种特殊类型,该类型将解决上面突出显示的问题,如下所示:

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

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

答案 6 :(得分:0)

在使用Angular的情况下,它们具有implemented Type,类似于Meirion Hughes answer

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

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

答案 7 :(得分:-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())