TypeScript 动态类使用具有不同参数的子类创建

问题描述 投票:0回答:1

我目前正在努力的挑战如下:

  1. 我从类型扩展为“Base”的端点接收模型 但可以是 12 个不同模型之一,并且每个模型都有一个类..
  2. 我有一个字符串可以帮助确定需要创建的类的类型
  3. 我有一个基类和子类

一些伪代码:

const result = api.call("get a model")  // can be of model type: "One" "Two" ... "Ten" which all extends 'BaseModel'

// value can be one of these: "One" "Two" ... "Ten" 
// will be a corresponding class for each 'modelType' which all extend a 'BaseClass'
const type:string = route.params.modelType

// createClass(type) - returns a class based on 'type' and 'result' is passed to its constructor
const newClass = new createClass(type)(result);

因此,我尝试根据字符串值动态创建类的新实例,使用构造函数中传递的模型来水合该类的属性,并将相同的模型传递给超类以水合类链上的属性。

问题是,当创建类并尝试在其构造函数中传递模型时,在将该对象传递给构造函数时出现可以理解的错误:

类型参数不可分配给类型参数。

我只是不确定如何解决它,或者是否可能?

这就是我目前所处的位置..

interface BaseModel {
    name: string;
    age: number
}

interface SubModel extends BaseModel {
    color: string;
    speed: number
}

interface SubModel2 extends BaseModel {
    shoeSize: number;
    height: number
}

class Base {

    name = '';
    age = 1;

    constructor(model: BaseModel) {
        this.name = model.name;
        this.age = model.age;
    }
}

class Sub extends Base {

    color = ''
    speed = 0;

    constructor(model: SubModel) {
        super(model);

        this.color = model.color;
        this.speed = model.speed;
    }

}

class Sub2 extends Base {

    shoeSize = 0;
    height= 0;

    constructor(model: SubModel2) {
        super(model);

        this.shoeSize = model.shoeSize;
        this.height = model.height;
    }

}

// ok: 
// const baseClass = new Base({ name: 'John', age: 39 });
// const subClass = new Sub({ color: 'green', speed: 100, ...baseClass });
// const sub2Class = new Sub2({ shoeSize: 10.5, height: 69, ...baseClass });


const Store = {
    ['Base']: Base,
    ['Sub']: Sub,
    ['Sub2']: Sub2,
};

class DynamicMenuElement {

    static instance: DynamicMenuElement;

    public static get() {
        if (!DynamicMenuElement.instance) {
            DynamicMenuElement.instance = new DynamicMenuElement();
        }
        return DynamicMenuElement.instance;
    }

    // *Something* should be in place of 'K' ...
    public createMenuElement<T extends keyof typeof Store, K extends BaseModel>(
        type: T, model: K
    ) {

        const Class = Store[type];
        if (!Class) {

            throw new Error(`Cannot find the class type of ${type}`);
        }
        return new Class(model); // error
    }
}

const base = { name: 'John', age: 39 };
const sub = { color: 'green', speed: 100, ...base };
const sub2 = { shoeSize: 10.5, height: 69, ...base };

// implementation
const element1 = DynamicMenuElement.get().createMenuElement('Base', base);
const element2 = DynamicMenuElement.get().createMenuElement('Sub', sub);
const element3 = DynamicMenuElement.get().createMenuElement('Sub', sub2); // should error

打字稿游乐场

typescript oop typescript-generics
1个回答
0
投票

这个这样的东西怎么样?我觉得有点笨重,但我认为它可以满足您的要求。

type ModelMap = {
    Base: BaseModel;
    Sub: SubModel;
    Sub2: SubModel2;
};

type ConstructorMap = {
    Base: typeof Base;
    Sub: typeof Sub;
    Sub2: typeof Sub2;
};

const Store: { [K in keyof ConstructorMap]: new (model: ModelMap[K]) => InstanceType<ConstructorMap[K]> } = {
    Base: Base,
    Sub: Sub,
    Sub2: Sub2,
};

class DynamicMenuElement {
    ...
    public createMenuElement<K extends keyof ConstructorMap>(
        type: K,
        model: ModelMap[K]
    ): InstanceType<ConstructorMap[K]> {
        const Class = Store[type];
        if (!Class) {
            throw new Error(`Cannot find the class type of ${type}`);
        }
        return new Class(model);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.