如何用枚举实现TypeScript多态工厂方法?
TypeScript 枚举关联参数类型的工厂方法实现
我有一个如下签名的工厂方法:
enum FactoryType { CAR = 'CAR', BIKE = 'BIKE' } type CarParamType = { cylinders: number } type BikeParamType = { gears: number } factory<F extends FactoryType>(factoryType: F, params: ParamType<F>) { switch (factoryType) { case FactoryType.CAR: return new CarFactory(params); case FactoryType.BIKE: return new BikeFactory(params); default: throw new Error('unrecognized factory'); } }其中
BikeFactory和CarFactory的构造函数会接收各自对应的参数类型。请问能否在TypeScript中实现这一需求?即通过枚举确定ParamType的实际类型,避免在工厂方法中将params传入对应构造函数时出现编译错误?我原本设想
ParamType的定义如下:type ParamType<T> = T extends FactoryType.CAR ? CarParamType : T extends FactoryType.BIKE ? BikeParamType : never;但我认为这样的定义无法为编译器提供足够的类型提示。
可以实现,优化方案如下
你的ParamType定义方向是对的,只需调整类型关联方式和工厂函数写法,就能让TypeScript正确识别枚举与参数类型的对应关系,解决编译错误的同时提供精准类型提示:
1. 用映射类型优化ParamType定义
先定义枚举到参数类型的映射表,比条件类型更直观,后续扩展枚举值时只需更新映射表:
// 枚举与参数类型的映射关系 type FactoryParamMap = { [FactoryType.CAR]: CarParamType; [FactoryType.BIKE]: BikeParamType; }; // 基于映射表定义ParamType type ParamType<T extends FactoryType> = FactoryParamMap[T];
2. 解决工厂函数的分支类型推导问题
TypeScript无法自动将泛型F extends FactoryType在switch分支中缩小到具体枚举值,可通过两种方式解决:
方案一:类型断言快速修复编译错误
如果追求实现简洁,直接在分支中给params添加类型断言即可:
class CarFactory { constructor(params: CarParamType) {} } class BikeFactory { constructor(params: BikeParamType) {} } function factory<F extends FactoryType>(factoryType: F, params: ParamType<F>) { switch (factoryType) { case FactoryType.CAR: return new CarFactory(params as CarParamType); case FactoryType.BIKE: return new BikeFactory(params as BikeParamType); default: throw new Error('unrecognized factory'); } }
方案二:函数重载实现精准类型提示
如果想要调用时自动关联参数类型、分支内无需断言,推荐使用函数重载:
// 重载签名:定义每种枚举对应的参数和返回类型 function factory(factoryType: FactoryType.CAR, params: CarParamType): CarFactory; function factory(factoryType: FactoryType.BIKE, params: BikeParamType): BikeFactory; // 实现签名:统一处理逻辑 function factory(factoryType: FactoryType, params: FactoryParamMap[FactoryType]) { switch (factoryType) { case FactoryType.CAR: return new CarFactory(params); case FactoryType.BIKE: return new BikeFactory(params); default: throw new Error('unrecognized factory'); } }
效果验证
调用工厂函数时,TypeScript会自动根据枚举值校验参数类型:
// 正确:参数匹配CAR类型 const car = factory(FactoryType.CAR, { cylinders: 6 }); // 错误:缺少cylinders参数,编译报错 const badCar = factory(FactoryType.CAR, {}); // 正确:参数匹配BIKE类型 const bike = factory(FactoryType.BIKE, { gears: 10 });
内容的提问来源于stack exchange,提问作者ThaDon
相关产品推荐
相关产品推荐

