如何用TypeScript泛型替代重载实现根据入参实例返回对应类型的工厂方法
用TypeScript泛型改写工厂方法的实现方案
class Car { brand = 'Skoda'; } class Human { name = 'Jan'; } class Garage { lots = 5; } class House { floors = 2; } class NotAllowed { anything = 'anything'; } // 定义入参类型到返回值类型的映射规则 type ResultFor<T> = T extends Car ? Garage : T extends Human ? House : never class Selection { // 泛型约束限制仅允许传入Car/Human实例 pick<T extends Car | Human>(what: T): ResultFor<T> { if (what instanceof Car) { return new Garage() as ResultFor<T> } else if (what instanceof Human) { return new House() as ResultFor<T> } throw Error('Not supported') } } const selection = new Selection(); selection.pick(new Car()).lots; // 编译器可正常自动补全 selection.pick(new Human()).floors // 编译器可正常自动补全 selection.pick(new NotAllowed()); // 触发编译器错误
实现说明
- 泛型约束
T extends Car | Human:限制pick方法的入参仅能是Car或Human的实例,传入其他类型(如NotAllowed实例)时直接触发编译错误,和原有重载的校验效果完全一致。 - 条件类型
ResultFor<T>:统一管理入参类型到返回值类型的映射规则,TS会自动根据传入的实参类型推断出对应的返回值类型,无需编写多组函数重载。 - 这里的类型断言是安全的:运行时的
instanceof判断已经保证了返回值和映射规则完全匹配,不会出现运行时类型错误。
扩展优化
如果后续需要新增更多的类型映射关系,仅需要调整三处即可,比维护多重重载更高效:
- 在泛型约束中新增允许的入参类型
- 在
ResultFor条件类型中新增对应返回值的映射分支 - 在运行时逻辑中新增对应的
instanceof判断分支
内容的提问来源于stack exchange,提问作者Jan Míšek
相关产品推荐
相关产品推荐

