TypeScript中基于实体数组实现getModel方法参数自动补全的需求
解决方案
我们可以通过类型推导、方法重载和运行时映射的结合,实现getModel方法的参数自动补全,同时支持实体构造函数和字符串两种参数类型:
type AnyParamConstructor<T> = new (...args: unknown[]) => T; class EntityA {} class EntityB {} class ModelA {} class ModelB {} // 提取构造函数的名称类型 type ClassName<T extends AnyParamConstructor<any>> = T["name"]; // 定义实体与对应Model的运行时映射,同时让TypeScript推导类型 const ENTITY_TO_MODEL_MAP = { [EntityA.name]: ModelA, [EntityB.name]: ModelB, } as const; // 从映射中提取类型,用于类型推导 type EntityToModel = typeof ENTITY_TO_MODEL_MAP; class Modeler<T extends AnyParamConstructor<any>> { // 运行时存储实体名称到实体构造函数的映射 private entityNameMap: Record<string, T> = {}; constructor(private entities: T[]) { // 初始化名称到实体的映射 entities.forEach(entity => { this.entityNameMap[entity.name] = entity; }); } // 方法重载1:接收实体构造函数参数,自动补全EntityA/EntityB public getModel<K extends T>(entity: K): EntityToModel[ClassName<K>]; // 方法重载2:接收实体名称字符串参数,自动补全"EntityA"/"EntityB" public getModel<K extends keyof EntityToModel>(entityName: K): EntityToModel[K]; // 方法实现逻辑 public getModel(arg: T | keyof EntityToModel) { // 判断参数类型,获取对应的实体名称 const targetName = typeof arg === "string" ? arg : arg.name; // 返回对应的Model构造函数 return ENTITY_TO_MODEL_MAP[targetName as keyof EntityToModel]; } } const modeler = new Modeler([EntityA, EntityB]); const modelA = modeler.getModel(EntityA); // 自动补全实体,返回ModelA类型 const modelAFromString = modeler.getModel("EntityA"); // 自动补全字符串,返回ModelA类型 const modelB = modeler.getModel(EntityB); // 返回ModelB类型 const modelBFromString = modeler.getModel("EntityB"); // 返回ModelB类型
核心实现要点:
类型推导:
- 用
ClassName<T>提取类的名称类型,让TypeScript能将实体构造函数和其名称字符串关联起来。 - 通过
as const标记ENTITY_TO_MODEL_MAP,让TypeScript保留具体的键值对类型,从而实现字符串参数的自动补全。
- 用
方法重载:
- 两个重载分别处理实体构造函数和字符串参数,确保两种参数都能获得IDE自动补全,同时返回正确的Model类型。
运行时映射:
entityNameMap在构造函数初始化时建立实体名称到实体的映射,后续若需扩展实体实例相关逻辑可直接复用。ENTITY_TO_MODEL_MAP存储实体名称到Model的映射,实现运行时的快速查找。
泛型约束:
Modeler<T extends AnyParamConstructor<any>>约束传入的实体必须是构造函数类型,确保类型安全。
内容的提问来源于stack exchange,提问作者Kleywalker
相关产品推荐
相关产品推荐

