Подтвердить что ты не робот

Передача класса в качестве параметра вызывает ошибку "не является новой"

Я пытаюсь передать класс как параметр некоторой функции, которая будет создавать экземпляр этого класса и возвращать его. Вот мой код:

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 type является конструктором объекта, как передать функцию конструктора во время выполнения?

4b9b3361

Ответ 1

Нам нужно что-то сказать 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");
}

Ответ 2

Попробуйте следующее:

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

Ответ 3

В дополнение к другим ответам; У меня есть тип утилиты, который я поддерживаю, чтобы обеспечить общий параметр /field - класс /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 - where T - общий тип - нет.

Например: register<T extends TViewBase>(view: typeof T) приводит к следующей ошибке:

[ts] 'T' относится только к типу, но используется здесь как значение.

Ответ 4

Есть два способа передать классы в TypeScript. Если вы:

  • знать суперкласс класса, через который вы проходите (уже рекомендованный Кори Аликс):

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

Ответ 5

Я знаю, что это старый вопрос, но здесь говорится:

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

Ответ был найден здесь.

Ответ 6

В зависимости от вашей ситуации ниже может не хватить трех вариантов решения:

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

Есть случаи, когда вы хотели бы вызвать некоторые статические методы, например myClass.someMethod(). 1 и 2 не позволят вам сделать это (и, пожалуйста, никогда не используйте их в вашем приложении), потому что они не знают об этом методе.

Или есть случаи, когда вы хотите иметь MyClass в качестве абстрактного класса и создавать экземпляр myClass с помощью let instance = new myClass. В этом случае 3 потерпит неудачу.

В этих случаях я создаю специальный тип для MyClass, который решает проблемы, которые я выделил выше, и выглядит примерно так:

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

КСТАТИ. Не забудьте добавить типы возврата к вашим методам, чтобы получить правильный смысл.

Ответ 7

если вы используете Angular, они реализовали Type, что похоже на ответ Мейриона Хьюза:

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

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

Ответ 8

Спасибо за суть - небольшое изменение заставляет все работать нормально. В приведенном ниже примере мы "обновляем" 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())