如何让TypeScript在函数体内关联约束两个字符串联合类型参数?
TypeScript中关联函数参数并实现函数体内类型推断
问题背景
需要关联函数的两个字符串联合类型参数,确保外部调用时能检查参数匹配性,同时在函数体内检查其中一个参数的值时,自动约束另一个参数的类型。
现有代码能正确处理外部调用的类型检查,但函数体内无法自动推断关联类型:
type A = "a_1" | "a_2" type B = "b_1" | "b_2" function foo<T extends A> (a: T, b: T extends "a_1" ? "b_1" : "b_2") { } // 外部调用检查正常 foo("a_1", "b_1") // 编译通过 foo("a_2", "b_2") // 编译通过 foo("a_1", "b_2") // 报错 foo("a_2", "b_1") // 报错
但函数体内检查a的值时,b的类型无法被正确窄化:
function foo<T extends A> (a: T, b: T extends "a_1" ? "b_1" : "b_2") { if (a == "a_1") { let bar: "b_1" = b // ^ 报错:类型"b_1" | "b_2"无法赋值给类型"b_1" } }
解决方案
使用可区分联合类型的元组定义参数的合法组合,让TypeScript明确关联两个参数的类型,同时支持函数体内的类型窄化:
type A = "a_1" | "a_2" type B = "b_1" | "b_2" // 定义参数的合法关联组合 type ParamPair = ["a_1", "b_1"] | ["a_2", "b_2"] function foo(...[a, b]: ParamPair) { if (a === "a_1") { let bar: "b_1" = b // 类型推断正确,无报错 console.log(bar) } else { // 此时a只能是"a_2",b自动推断为"b_2" let bar: "b_2" = b // 无报错 console.log(bar) } } // 外部调用依然保持严格检查 foo("a_1", "b_1") // 正常 foo("a_2", "b_2") // 正常 foo("a_1", "b_2") // 报错:类型不匹配 foo("a_2", "b_1") // 报错:类型不匹配
原理说明
这种方式利用了TypeScript对可区分联合类型的支持:
- 将参数的合法组合枚举为元组联合类型,每个元组内的两个参数类型强关联
- 当通过条件判断
a === "a_1"窄化a的类型时,TypeScript会自动将对应的b的类型窄化为"b_1" - 相比泛型条件类型的写法,联合元组直接明确了所有合法的参数组合,避免了泛型参数在函数体内无法被反向约束的问题
内容的提问来源于stack exchange,提问作者Niki Herl
相关产品推荐
相关产品推荐

