Динамическая загрузка класса 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)
}
Ответы
Ответ 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();