TypeScript中基于枚举键的工厂函数类型推断优化问询
解决TypeScript工厂函数的类型标注问题
要同时实现switch分支内payload类型验证和调用时精确的返回类型推断,最优雅的方式是使用函数重载,它能完美匹配你的需求。下面是具体的实现方案:
完整代码示例
首先保留你定义的枚举、接口和类型:
enum keys { key1 = 1, key2 = 2 } interface Test1 { key: keys.key1; payload: string; } interface Test2 { key: keys.key2; payload: number; } type tests = Test1 | Test2; interface ReturnTypeOfTest1 { returnedObject1: number; } interface ReturnTypeOfTest2 { returnedObject2: string; } interface ModelOfTest { [keys.key1]: ReturnTypeOfTest1; [keys.key2]: ReturnTypeOfTest2; }
实现正确类型标注的工厂函数
// 重载签名:明确每个输入类型对应的精确返回类型 function getTest(t: Test1): ReturnTypeOfTest1; function getTest(t: Test2): ReturnTypeOfTest2; // 实现签名:处理联合类型输入,内部通过switch窄化类型 function getTest(t: tests): ModelOfTest[keys] { switch (t.key) { case keys.key1: { const data = t.payload; // 类型自动推断为string ✅ return { returnedObject1: 123 }; // 类型检查符合ReturnTypeOfTest1 ✅ } case keys.key2: { const data = t.payload; // 类型自动推断为number ✅ return { returnedObject2: '123' }; // 类型检查符合ReturnTypeOfTest2 ✅ } default: // 兜底处理未知枚举键,避免编译错误 throw new Error(`Unsupported key: ${t.key}`); } }
调用效果验证
调用时TypeScript会自动推断精确的返回类型,同时严格检查payload的类型:
// 返回类型为ReturnTypeOfTest1,payload必须是string const res1 = getTest({ key: keys.key1, payload: 'hello' }); console.log(res1.returnedObject1); // 类型安全,不会提示不存在的属性 // 返回类型为ReturnTypeOfTest2,payload必须是number const res2 = getTest({ key: keys.key2, payload: 456 }); console.log(res2.returnedObject2); // 同样类型安全
为什么之前的写法有缺陷?
- 第一种写法:用
tests作为参数类型时,switch分支能通过key窄化参数类型,所以payload类型正确,但返回类型用any或联合类型,丢失了调用时的精确类型推断。 - 第二种写法:泛型
T extends tests虽然能让返回类型精确,但TypeScript无法在泛型函数的switch分支内将泛型T窄化到具体的Test1或Test2,导致payload类型变成联合类型,返回值也要求符合所有可能返回类型的交集,从而报错。
而函数重载通过明确的输入输出类型映射,既满足了内部分支的类型验证,又保证了外部调用的精确类型推断。
内容的提问来源于stack exchange,提问作者cuddlemeister
相关产品推荐
相关产品推荐

