You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript动态创建类并根据首个参数约束第二个参数类型

动态类实例化的类型约束问题

需求说明

需要实现一个方法,根据传入的枚举值动态实例化对应类,第二个参数必须严格匹配该类构造函数所需的Model类型。例如传入MenuElement.Products时,第二个参数只能传入ProductModel对象。

现有代码

enum MenuElement {
    Categories = 'Categories',
    Products = 'Products',
}

type ProductModel = {
  name:string;
  age:number
   id:string;
}
type CategoryModel = {
  name:string;
  favorite:boolean
   id:string;
}

class Product implements ProductModel{
  name =''
  age= 0;
  id = '';

  constructor(model:ProductModel)
  {
  }
}

class Category implements CategoryModel{
  name=''
  favorite=true
  id=''

  constructor(model:CategoryModel)
  {
  }
}

const MenuElements = {
  [MenuElement.Products]:Product,
  [MenuElement.Categories]:Category
}

type KeysInEnum = keyof typeof MenuElement

type ModelTypeForNewElement<Z extends keyof typeof MenuElements, Type extends typeof MenuElements[Z]> = {
    [Prop in keyof Type]: Type[Prop];
}

type GEN = keyof typeof MenuElement;

class DynamicMenuElement {
    static instance: DynamicMenuElement;

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

    public createMenuElement<T extends GEN>(type: T, model: ModelTypeForNewElement<T,typeof MenuElements[T]>) {

        const ElementType = MenuElements[type]
        if (!ElementType) {

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

    }
}

const creator = DynamicMenuElement.get();

creator.createMenuElement(MenuElement.Categories,/*代码提示需要Category Model(符合预期) */)

creator.createMenuElement(MenuElement.Products,/*代码提示需要Product Model(符合预期) */)

当前问题

代码中ElementType的类型被自动推断为:

const ElementType: new (model: ProductModel & CategoryModel) => Product | Category

但预期的类型应该是:

const ElementType: new (model: ProductModel | CategoryModel) => Product | Category

参数被合并为所有Model的交叉类型,而非符合逻辑的联合类型,导致类型校验不符合预期。

解决方案

通过显式建立枚举值、类、Model的一一映射关系,避免TypeScript自动合并类型时产生错误推断:

enum MenuElement {
    Categories = 'Categories',
    Products = 'Products',
}

type ProductModel = {
  name:string;
  age:number
   id:string;
}
type CategoryModel = {
  name:string;
  favorite:boolean
   id:string;
}

class Product implements ProductModel{
  name =''
  age= 0;
  id = '';

  constructor(model:ProductModel) {}
}

class Category implements CategoryModel{
  name=''
  favorite=true
  id=''

  constructor(model:CategoryModel) {}
}

// 显式定义枚举与类、Model的映射关系
type MenuElementMap = {
  [MenuElement.Categories]: { cls: typeof Category; model: CategoryModel };
  [MenuElement.Products]: { cls: typeof Product; model: ProductModel };
};

const MenuElements: MenuElementMap = {
  [MenuElement.Products]: { cls: Product, model: {} as ProductModel },
  [MenuElement.Categories]: { cls: Category, model: {} as CategoryModel }
};

class DynamicMenuElement {
    static instance: DynamicMenuElement;

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

    // 利用泛型约束实现精准的类型匹配
    public createMenuElement<T extends keyof MenuElementMap>(
      type: T, 
      model: MenuElementMap[T]['model']
    ) {
        const elementEntry = MenuElements[type];
        if (!elementEntry) {
            throw new Error(`Cannot find the class type of ${type}`);
        }
        return new elementEntry.cls(model);
    }
}

const creator = DynamicMenuElement.get();

// 自动提示并校验CategoryModel参数
creator.createMenuElement(MenuElement.Categories, {
  name: 'Food',
  favorite: true,
  id: '1'
});

// 自动提示并校验ProductModel参数
creator.createMenuElement(MenuElement.Products, {
  name: 'Apple',
  age: 1,
  id: '2'
});

关键改动说明

  • 新增MenuElementMap类型,明确建立枚举值与对应类、Model的一一绑定,避免TypeScript自动合并类型时生成交叉类型。
  • 调整MenuElements对象的类型为MenuElementMap,确保每个枚举值对应的条目类型准确。
  • 在createMenuElement方法中,通过MenuElementMap[T]['model']直接获取当前枚举值对应的Model类型,实现参数的精准约束,同时实例化时的类型推断也会正确匹配到具体类。

内容的提问来源于stack exchange,提问作者VarJohn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 19:57:00