Home > Net >  Dynamic creation classes instances from array (Typescript)
Dynamic creation classes instances from array (Typescript)

Time:09-12

I need to instantiate components on the fly. But I don't understand how to make it work. As I understand need "cast"? Or is there a more elegant solution?

abstract class Component{
    abstract mount(): void;
}

class ComponentA extends Component{
    mount(){}
    send(){}
}

class ComponentB extends Component{
    mount(){}
}

type Components = {
    componentA: ComponentA,
    componentB: ComponentB
}

const componentsName = [ComponentA, ComponentB];
const instances = {} as Components;

for(const component of componentsName){
    instances[component.name] = new component(); //how to cast?
    //Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Components'.
    //No index signature with a parameter of type 'string' was found on type 'Components'.(7053)
}

function getComponent <T extends keyof Components>(componentName: T): Components[T] {
    return instances[componentName];
}

//test 1
const componentA = instances.componentA
const componentB = instances.componentB

//test 2
const componentA2 = getComponent("componentA").send //mount | send
const componentB2 = getComponent("componentB").mount //only mount

Typescript playground

CodePudding user response:

I had to configure ES2019 support in the TS playground (because of Object.fromEntries) and I don't know if this solution would be ok for you, because it basically just uses a type-cast as you did before.

In addition there was the problem in your code that component.name of e.g. ComponentA is "ComponentA" and not as you wanted "componentA". That is fixed below, too.

abstract class Component{
    abstract mount(): void;
}

class ComponentA extends Component{
    mount(){}
    send(){}
}

class ComponentB extends Component{
    mount(){}
}

type Components = {
    componentA: ComponentA,
    componentB: ComponentB
}

const componentsName = [ComponentA, ComponentB] as const;
const instances = Object.fromEntries(componentsName.map((component) => [component.name[0].toLowerCase()   component.name.substring(1), new component()])) as Components;

function getComponent <T extends keyof Components>(componentName: T): Components[T] {
    return instances[componentName];
}

//test 1
const componentA = instances.componentA
const componentB = instances.componentB

//test 2
const componentA2 = getComponent("componentA").send //mount | send
const componentB2 = getComponent("componentB").mount //only mount

TypeScript Playground

  • Related