泛型与联合类型结合时Record无法索引的问题排查与解决
TypeScript泛型与联合类型索引错误问题解析
异常原因
当泛型约束为联合类型Both时,TypeScript无法追踪T['keys']和T['value']之间的关联关系:
T extends Both意味着T可以是A或C,TypeScript会将T['keys']解析为'a'|'b'|'c'|'d',T['value']解析为{a:string,b:string} | {c:string,d:string}。- 此时类型系统无法保证传入的
key一定属于当前def的键集合(比如可能用'a'索引{c:string,d:string}),因此抛出索引错误。 - 当约束改为
T extends A或T extends C时,keys和value的关联是明确的,类型系统能确认key是value的有效键,所以不会报错。
正确实现方案
方案一:保留泛型关联关系
直接用Foo作为泛型约束,明确keys和value的绑定:
type Foo<K extends string, T extends Record<K, string>> = { keys: K value: T } type A = Foo<'a'|'b', {'a': 'A', 'b':'B'}> type C = Foo<'c'|'d', {'c': 'C', 'd':'D'}> function bar<K extends string, T extends Record<K, string>>(def: T, key: K) { return def[key]; } // 调用示例 const aValue: A['value'] = {a: 'A', b: 'B'}; bar(aValue, 'a'); // 正常通过类型检查 bar(aValue, 'c'); // 类型报错,符合预期
方案二:基于联合类型的分布式处理
如果需要保留Both联合类型的约束,可使用分布式条件类型确保类型关联:
type Foo<K extends string, T extends Record<K, string>> = { keys: K value: T } type A = Foo<'a'|'b', {'a': 'A', 'b':'B'}> type C = Foo<'c'|'d', {'c': 'C', 'd':'D'}> type Both = A|C function bar<T extends Both>(def: T['value'], key: T['keys']): T extends {value: infer V, keys: infer K} ? K extends keyof V ? V[K] : never : never { return def[key as any]; } // 调用示例 const aValue: A['value'] = {a: 'A', b: 'B'}; const cValue: C['value'] = {c: 'C', d: 'D'}; bar(aValue, 'a'); // 返回类型为'A' bar(cValue, 'd'); // 返回类型为'D' bar(aValue, 'c'); // 类型报错,符合预期
内容的提问来源于stack exchange,提问作者Dean Xu
相关产品推荐
相关产品推荐

