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

Динамическая загрузка класса typescript (отражение для typescript)

Я хотел бы иметь возможность создавать экземпляр класса typescript, где я получаю данные о классе и конструкторе во время выполнения. Функция, которую я хотел бы написать, будет принимать параметры класса и конструктора.

export function createInstance(moduleName : string, className : string, instanceParameters : string[]) {
    //return new [moduleName].[className]([instancePameters]); (THIS IS THE BIT I DON'T KNOW HOW TO DO)
}
4b9b3361

Ответ 1

Вы можете попробовать:

var newInstance = Object.create(window[className].prototype);
newInstance.constructor.apply(newinstance, instanceparameters);
return newInstance;

Изменить. Эта версия работает с игровой площадкой TypeScript с примером:

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

//instance creation here
var greeter = Object.create(window["Greeter"].prototype);
greeter.constructor.apply(greeter, new Array("World"));

var button = document.createElement('button');
button.innerText = "Say Hello";
button.onclick = function() {
    alert(greeter.greet());
}

document.body.appendChild(button);

Ответ 2

Когда вы используете TypeScript, я предполагаю, что вы хотите, чтобы загруженный объект был введен. Итак, вот пример класса (и интерфейс, потому что вы, например, выбираете загрузку одной из многих реализаций).

interface IExample {
    test() : string;
}

class Example {
    constructor (private a: string, private b: string) {

    }

    test() {
        return this.a + ' ' + this.b;
    }
}

Итак, вы использовали бы какой-то загрузчик, чтобы вернуть вам реализацию:

class InstanceLoader {
    constructor(private context: Object) {

    }

    getInstance(name: string, ...args: any[]) {
        var instance = Object.create(this.context[name].prototype);
        instance.constructor.apply(instance, args);
        return instance;
    }
}

И затем загрузите его следующим образом:

var loader = new InstanceLoader(window);

var example = <IExample> loader.getInstance('Example', 'A', 'B');
alert(example.test());

На данный момент у нас есть актерский состав: <IExample> - но когда добавлены дженерики, мы можем покончить с этим и вместо этого использовать дженерики. Это будет выглядеть (учитывая, что это еще не часть языка!)

class InstanceLoader<T> {
    constructor(private context: Object) {

    }

    getInstance(name: string, ...args: any[]) : T {
        var instance = Object.create(this.context[name].prototype);
        instance.constructor.apply(instance, args);
        return <T> instance;
    }
}

var loader = new InstanceLoader<IExample>(window);

var example = loader.getInstance('Example', 'A', 'B');

Ответ 3

Если у вас есть определенное пространство имен/модуль, для всех классов, которые вы хотите создать, вы можете просто сделать это:

var newClass: any = new MyNamespace[classNameString](parametersIfAny);

Обновление: без использования пространства имен new window[classname]()

В TypeScript, если вы объявляете класс за пределами пространства имен, он генерирует var для "функции класса". Это означает, что он хранится в соответствии с текущей областью (скорее всего, window, если вы не запускаете ее под другой областью, например, nodejs). Это означает, что вы можете просто сделать new window[classNameString]:

Это рабочий пример (весь код, без пространства имен):

class TestClass
{
    public DoIt()
    {
        alert("Hello");
    }
}

var test = new window["TestClass"]();
test.DoIt();

Чтобы понять, почему это работает, сгенерированный JS-код выглядит следующим образом:

var TestClass = (function () {
    function TestClass() {
    }
    TestClass.prototype.DoIt = function () {
        alert("Hello");
    };
    return TestClass;
}());
var test = new window["TestClass"]();
test.DoIt();

Ответ 4

Это работает в TypeScript 1.8 с модулем ES6:

import * as handlers from './handler';

function createInstance(className: string, ...args: any[]) {
  return new (<any>handlers)[className](...args);
}

Классы экспортируются в модуль handler. Они могут быть реэкспортированы из других модулей.

export myClass {};
export classA from './a';
export classB from './b';

Что касается пропущенного имени модуля в пресс-релизах, я не могу заставить его работать, потому что модуль ES6 не может быть динамически загружен.

Ответ 5

По состоянию на typescript 0.9.1 вы можете сделать что-то вроде playground:

class Handler {
    msgs:string[];  
    constructor(msgs:string[]) {
        this.msgs = msgs;
    }
    greet() {
        this.msgs.forEach(x=>alert(x));
    }
}

function createHandler(handler: typeof Handler, params: string[]) {
    var obj = new handler(params);
    return obj;
}

var h = createHandler(Handler, ['hi', 'bye']);
h.greet();