通过唯一属性区分联合类型:TypeScript如何缩小响应类型?
解决TypeScript联合类型函数输入输出类型关联问题
给定通过method字段区分的联合类型:
type Actions = { method: "connections", request: number, response: number, } | { method: "delete", request: string, response: string, }
希望编写函数接收对应method的request参数,返回匹配类型的response,但当前定义的泛型函数:
type Fn = <A extends Actions>(a: Pick<A, 'method' | 'request'>) => Pick<A, 'method' | 'response'>;
调用时无法自动缩小response类型:
const x = fn({ method: "connections", request: 10 }) x.response // 类型为 string | number,而非预期的number
以下是无需再次检查method即可实现类型精准匹配的解决方案:
方案1:通过Extract关联method对应子类型
将泛型约束绑定到method的字面量类型,用Extract从联合类型中提取对应method的子类型,确保输入输出类型严格关联:
type Fn = <M extends Actions['method']>( a: Pick<Extract<Actions, { method: M }>, 'method' | 'request'> ) => Pick<Extract<Actions, { method: M }>, 'method' | 'response'>;
方案2:用映射类型重构关联关系
先将Actions转换为以method为键的映射类型,让类型关联更直观:
// 构建method到请求响应类型的映射 type ActionMap = { [A in Actions as A['method']]: Omit<A, 'method'> }; // 定义函数类型 type Fn = <M extends keyof ActionMap>( a: { method: M } & { request: ActionMap[M]['request'] } ) => { method: M } & { response: ActionMap[M]['response'] };
效果验证
调用时TypeScript会自动根据method推断出正确的response类型:
const x = fn({ method: "connections", request: 10 }); x.response; // 类型为number(符合预期) const y = fn({ method: "delete", request: "user-id-123" }); y.response; // 类型为string(符合预期)
原写法问题分析
原泛型A extends Actions的约束过于宽泛,TypeScript无法精准推断出传入参数对应的具体联合成员,导致返回值的response仍保留联合类型。绑定泛型到method字面量后,能强制TypeScript锁定到对应子类型,实现输入输出的类型强关联。
内容的提问来源于stack exchange,提问作者bohemak2
相关产品推荐
相关产品推荐

