Dynamically loading a typescript class (reflection for typescript)
You could try:
var newInstance = Object.create(window[className].prototype);
newInstance.constructor.apply(newInstance, instanceparameters);
return newInstance;
Edit This version is working using the TypeScript playground, with the example:
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);
Dynamically generate and return a class object
There are several possible solutions, it depends how much "automated" the solution should be.
1) Simple
Using mapping, similar to AdityaParab's answer.
class Product1 {}
class Product2 {}
class Product3 {}
// Mapping from type name to class object.
const ProductMap = {
prod1: Product1,
prod2: Product2,
prod3: Product3
};
function getProductByType(type) {
const Product = ProductMap[type];
if (!Product) throw new Error(`Unknown ProductType '${type}'.`);
return new Product(type);
}
console.log(getProductByType("prod1"));
2) Real Reflection (requires TypeScript transformer)
StackBlitz demo here.
Check out tst-reflection GitHub repo.
Decorator used to mark Product classes.
/**
* Decorator used to mark Product classes.
* @reflect - required JSDoc property. Means all decorated types can be used in reflection.
* @param productType
*/
export function ForProductType(productType: string) {
return (ctor: Function) => {};
}
Decorated Product class.
@ForProductType('prod1')
export class Product1 implements Product {
readonly type: string = 'prod1';
get name() {
return 'Product 1';
}
}
getProductByType function with a little bit of reflection.
// Some reflection job.. Find all types decorated by the ForProductType decorator and create map of those types.
const entries = Type.getTypes()
.map<[string, Type]>((type) => [
type
.getDecorators()
.find((decorator) => decorator.name == 'ForProductType')
?.getArguments()[0],
type,
])
.filter(([typeName, type]) => !!typeName);
const ProductTypeMap = new Map<string, Type>(entries);
function getProductByType(type: string): Promise<Product> {
const ProductType: Type = ProductTypeMap.get(type);
if (!ProductType) {
throw new Error(`Unknown ProductType '${type}'.`);
}
return ProductType.getCtor().then((Product) => new Product());
}
Usage
getProductByType('prod1').then((product) => console.log(product, product.name));
It returns Promise cuz it does dynamic imports of the Product classes.
Typescript reflection inside a namespace
Hah, asking the question led me to see the light. I think. The trick was to export the classes, duh.
namespace Test {
interface INamed {
name:string;
}
export class Foo implements INamed {
name:string;
constructor( name:string ) {
this.name = name;
}
}
export class Bar implements INamed {
name:string;
constructor( name:string ) {
this.name = name;
}
}
export function factory( className:string ):INamed {
return new Test[className]( className + " instance" );
}
}
var bar = Test.factory( "Bar" );
console.log( bar.name );
How to get a class from a string in TypeScript/JavaScript in an Angular 2 application?
This sounds like a reflection question in typescript.
Possibly you could check this out if you haven't
Dynamically loading a typescript class (reflection for typescript)
Angular2 typescript create new object dynamically with class name from variable?
There are a few ways to do this. If your class is in a separate module:
SomeClass.ts
export class SomeClass {
constructor(arg: string) {
console.log(arg);
}
}
App.ts
import * as s from "./SomeClass";
var instance = new s["SomeClass"]("param");
Or using namespaces:
namespace Test {
export class SomeClass {
constructor(arg: string) {
console.log(arg);
}
}
}
var instance = new Test["SomeClass"]("param");
javascript dynamically create class instance from a class name
Use the apply invocation pattern or Function.prototype.call
:
function createBlock (divName, className){
var myDiv = document.createElement("div")
myDiv.id = divName;
document.body.appendChild(myDiv);
var block = className.call(null, myDiv);
return block;
}
This will require both constructor functions, Header
and Footer
, to be scope-safe by checking for this
function Header(arg) {
if(this instanceof Header) {
//initialise
return this;
}
else {
return new Header(arg);
}
}
Related Topics
Drawing a Line with Three.Js Dynamically
Reading JavaScript Variable into Shiny/R on App Load
Most Efficient Method of Detecting/Monitoring Dom Changes
How to Create an Object from an Array of Key-Value Pairs
Template Literal Inside of the Regex
How to Save a Leaflet Map with Drawn Shapes/Points on It in Shiny
Is There a Version of JavaScript's String.Indexof() That Allows for Regular Expressions
How to Update Single Value Inside Specific Array Item in Redux
Change Second Select List Based on First Select List Value in Rails
Simple Component Is Not Rendering: React Js
Why am I Getting Weird Result Using Parseint in Node.Js? (Different Result from Chrome Js Console)
Leaderboard Ranking with Firebase
How to Check If Function Exists in JavaScript
Js.Erb Not Executing JavaScript But Is Processed Rails
Maintain Model of Scope When Changing Between Views in Angularjs
Firebase Cloud Function Won't Store Cookie Named Other Than "_Session"