TypeScript中如何让switch语句自动推断props类型?
解决方案:TypeScript中switch分支自动推断props类型
问题场景
我编写了包含多个interface、组件及PropsMap的TypeScript代码,在MyFunc函数的switch语句中,希望TypeScript能根据传入的key自动推断props的对应类型,无需手动写类型断言。试过泛型映射方案但未成功,目前给每个key创建类型守卫能实现需求,但过于繁琐,想找更简洁的解决办法。
原始代码
interface FooProps { 'keyInFoo': string } const Foo = (props: FooProps) => {} interface BarProps { 'keyInBar': string } const Bar = (props: BarProps) => {} interface PropsMap { 'foo': FooProps, 'bar': BarProps, //.. baz, etc... } type keyName = keyof PropsMap const MyFunc = <T extends keyName>(key: T) => { const props: PropsMap[T] = getProps(key) switch(key) { // 理论上T为'foo'时,props应该是FooProps case 'foo': return Foo(props) // <- 错误:类型'BarProps'中缺少属性'keyInFoo' case 'bar': return Bar(props) // <- 错误:类型'FooProps'中缺少属性'keyInBar' } } const getProps = <T extends keyName>(key: T): PropsMap[T] => { // ... 获取props的业务逻辑 return {} as PropsMap[T] }
试过的方案
泛型映射类型(无效)
尝试用条件泛型做类型映射,但没有达到预期效果:
type PropsGeneric<T extends keyName> = T extends 'foo' ? FooProps : T extends 'bar' ? BarProps : never;
类型守卫方案(可行但繁琐)
给每个key单独写类型守卫,再用if-else if语句判断:
const isFoo = <T extends keyName>(key: T, props: PropsMap[T]): props is FooProps => key === 'foo' const isBar = <T extends keyName>(key: T, props: PropsMap[T]): props is BarProps => key === 'bar' // ... 更多key对应的类型守卫
简洁解决方案
核心思路是让TypeScript建立key和props的类型关联,利用字面量类型收窄特性,让switch/if分支自动识别对应类型。
方案1:直接用if分支收窄类型
不需要额外定义类型守卫,直接通过判断key的字面量值,TypeScript会自动收窄props的类型:
const MyFunc = <T extends keyName>(key: T) => { const props = getProps(key); if (key === 'foo') { // 自动推断props为FooProps return Foo(props); } else if (key === 'bar') { // 自动推断props为BarProps return Bar(props); } }
方案2:用联合类型元组关联key与props
如果偏好使用switch语句,可以通过构造联合类型元组,让TypeScript同时收窄key和props的类型:
// 先定义组件与key的映射(可选,用于统一管理) const ComponentMap = { foo: Foo, bar: Bar, // ... 其他组件 } as const; // 生成联合类型,关联key、组件、props的对应关系 type ComponentEntry = { [K in keyof typeof ComponentMap]: [K, typeof ComponentMap[K], PropsMap[K]] }[keyof typeof ComponentMap]; const MyFunc = <T extends keyName>(key: T) => { const props = getProps(key); // 构造元组,让TypeScript建立key与props的类型关联 const entry = [key, ComponentMap[key], props] as ComponentEntry; switch(entry[0]) { case 'foo': // 自动推断entry[2]为FooProps return entry[1](entry[2]); case 'bar': // 自动推断entry[2]为BarProps return entry[1](entry[2]); } }
原理说明
TypeScript的类型收窄依赖值的字面量判断:当你在if/switch分支中明确判断key是某个具体字面量时,TypeScript会自动将泛型T收窄为该字面量类型,进而PropsMap[T]也会被同步收窄为对应的props类型,无需手动断言。
内容的提问来源于stack exchange,提问作者Adam Thompson
相关产品推荐
相关产品推荐

