如何传递泛型类型数组并让每个元素的泛型类型被正确推断?
TypeScript数组中Entry类型的正确校验方案
问题背景
首先定义以下TypeScript类型:
type ValueMap = { foo: 'FOO1' | 'FOO2'; bar: 'BAR1' | 'BAR2' | 'BAR3'; }; type Key = keyof ValueMap; type Value<K extends Key> = ValueMap[K]; type Entry<K extends Key> = { key: K; value: Value<K>; }
Entry类型的key与value存在严格对应关系:比如{key: 'foo', value: 'FOO2'}是合法的,但{key: 'foo', value: 'BAR3'}不合法。
但当尝试将这类Entry组成数组传入sendArray函数时,当前实现无法正确推断每个元素的泛型类型:
function sendArray<K extends Key>(v: Array<Entry<K>>) { // ... } sendArray([{key: 'foo', value: 'FOO2'}, {key: 'bar', value: 'BAR1'}]) sendArray([{key: 'foo', value: 'FOO2'}, {key: 'bar', value: 'FOO1'}]) // 错误编译通过
此时泛型K会被推断为"foo" | "bar",导致value的类型变成所有可能值的联合,失去了单个元素的校验能力。
解决方案
方法一:直接使用联合类型数组
修改函数参数类型为Array<Entry<Key>>,让数组元素接受Entry<'foo'>或Entry<'bar'>的联合类型,TypeScript会逐个校验每个元素的key与value对应关系:
function sendArray(v: Array<Entry<Key>>) { // ... } sendArray([{key: 'foo', value: 'FOO2'}, {key: 'bar', value: 'BAR1'}]); // 合法 sendArray([{key: 'foo', value: 'FOO2'}, {key: 'bar', value: 'FOO1'}]); // 类型错误,符合预期
方法二:带泛型约束的实现(保留泛型能力)
如果需要保留泛型以获取数组的具体类型信息,可以用泛型参数约束为Entry<Key>的数组:
function sendArray<T extends Entry<Key>[]>(v: T) { // 可通过泛型T获取数组的具体类型 }
这种写法同样能保证每个元素的key与value匹配,同时保留泛型带来的类型推断能力。
原理说明
原写法中Array<Entry<K>>要求数组内所有元素的K必须是同一类型(或其联合),因此TypeScript会把K推断为'foo' | 'bar',导致value的类型宽松为所有可能值的联合,失去校验效果。
修改后的写法让数组元素接受Entry<Key>联合类型,TypeScript会对每个元素单独进行类型检查,确保每个元素的key对应正确的value范围,从而实现精准校验。
内容的提问来源于stack exchange,提问作者JHH
相关产品推荐
相关产品推荐

