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

hgb9j2n6  于 2023-06-24  发布在  TypeScript
关注(0)|答案(8)|浏览(175)

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

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.

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

e7arh2l6

e7arh2l61#

在函数签名中,我们需要用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");
}
qzwqbdag

qzwqbdag2#

补充其他答案;我有一个实用程序类型,以确保泛型参数/字段是一个类/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]“T”仅引用类型,但在此处用作值。

ua4mk5z4

ua4mk5z43#

试试这个:

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

flseospp4#

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

*知道你要经过的类的超类(Corey阿利克斯已经推荐):

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);
xzabzqsa

xzabzqsa5#

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

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

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

ioekq8ef6#

我知道这是一个老问题,但我还是要说:

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

找到答案here

xbp102n0

xbp102n07#

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

  1. myClass: new (name: string) => MyClass
  2. interface IMyClass { new (name: string): MyClass; }; myClass: IMyClass
  3. myClass: typeof MyClass
    在某些情况下,您希望调用一些static方法,如myClass.someMethod()12不允许你这样做(请不要在你的应用程序中使用任何),因为他们不知道这个方法。
    或者在某些情况下,您希望将MyClass作为一个抽象类,并使用let instance = new myClass创建myClass的示例。在这种情况下,3将失败。
    在这些情况下,我所做的是为MyClass创建一个特殊的类型,以解决我上面强调的问题,它看起来像这样:
    type MyClassContructor<T extends MyClass> = typeof MyClass & Constructor<T>;
    顺便说一句,别忘了给你的方法添加返回类型,这样你就能得到正确的智能感知。
yfjy0ee7

yfjy0ee78#

谢谢你的大意-一个小小的改变就能让一切都工作得很好。在下面的例子中,我们“新建”了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())

相关问题