Передача класса в качестве параметра вызывает ошибку "не является новой"
Я пытаюсь передать класс как параметр некоторой функции, которая будет создавать экземпляр этого класса и возвращать его. Вот мой код:
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 является конструктором объекта, как передать функцию конструктора во время выполнения?
Ответы
Ответ 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
В зависимости от вашей ситуации ниже может не хватить трех вариантов решения:
myClass: new (name: string) => MyClass
interface IMyClass {
new (name: string): MyClass;
};
myClass: IMyClass
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())