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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12802317/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 00:51:31  来源:igfitidea点击:

Passing class as parameter causes "is not newable" error

typescript

提问by zw0rk

I'm trying to pass a class as a parameter to some function, that will instantiate this class and return it. Here is my code:

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

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

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

When i'm trying to compile this, i'm getting:

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

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

What am I doing wrong?

我究竟做错了什么?

If a newable type value is an object constructor how do i pass the constructor function at runtime?

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

回答by Thomas Laurent

We need something to say typeof(MyClass) to distinguish objects from classes in function signatures.

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

Anyway, you can actually solve you problem by using constructor type signature. Considering this class:

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

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

To pass that class as a type that you can then instantiate in a function, you actually have to duplicate the class constructor signature like this:

要将该类作为可以在函数中实例化的类型传递,您实际上必须像这样复制类构造函数签名:

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

EDIT :There is a simple solution found on codeplex:

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

You have to create an interface for your class like this:

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

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

Then, use it in your function signature:

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

function sample(MyClass: IMyClass) {
    var obj = new MyClass("hello");
}

回答by Matthew James Davis

Try this:

尝试这个:

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

回答by Meirion Hughes

To supplement the other answers; I have a utility type I keep around to ensure a generic parameter/field is a class/newable:

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

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

You can then ensure you get a class constructor:

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

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

the Newable<T>approach works where typeof T--where Tis a generic type-- does not.

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

For example: register<T extends TViewBase>(view: typeof T)results in the following error:

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

[ts] 'T' only refers to a type, but is being used as a value here.

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

回答by Stephen Paul

There are 2 ways to pass classes in TypeScript. If you:

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

  • know the superclass of the class you're passing through(already recommended by Corey Alix):

    class MyClass extends MySuperClass{ }
    
    makeMyClass(classRef: typeof MySuperclass) {
        return new classRef();
    }
    
    makeMyClass(MyClass);
    
  • know the signature of the class's constructor function:

    class MyClass {
        constructor(arg: string) {}
    }
    
    makeMyClass(classRef: { new(arg: string) }) {
        return new classRef('hello');
    }
    
    makeMyClass(MyClass);
    
  • 知道您正在通过的类的超类(已由 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);
    

回答by Perspectivus

I know this is an old question, but here goes:

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

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

Answer was found here.

答案在这里找到。

回答by ya_dimon

in case you use Angular, they have implementedType, its similar to the Meirion Hughes answer:

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

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

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

回答by Ionel Lupu

Depending on your situation, the three solution bellow might not be enough:

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

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

There are cases where you would like to call some staticmethods like myClass.someMethod(). 1and 2won't allow you to do that (and pls never use any in your app) because they don't know about that method.

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

Or there are cases when you want to have MyClassas an abstractclass and create an instance of myClass with let instance = new myClass. In that case, 3will fail.

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

What I do in these cases is to create a special type for MyClassthat will solve the issues I highlighted above, which looks something like this:

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

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

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

BTW. Don't forget to add return types to your methods so you get proper intellisense.

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

回答by Fenton

Thank you for the gist - a slight change makes it all work fine. In the example below, we "new up" the TestViewto pass in the concrete test view, rather than trying to new it within the method.

感谢您提供的要点 - 稍作更改即可使其一切正常。在下面的示例中,我们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())