TypeScript编写访问嵌套对象键的函数时无法访问属性问题
嵌套对象属性访问的TS类型报错修复
问题场景
需要实现一个接收key和subKey两个参数的函数,用来访问嵌套存储对象的对应属性,已经完成了基础类型定义,但函数内部无法正常访问目标对象的myFunction、someData属性。
问题复现代码
type ObjectDefinationType<T> = { myFunction: () => void; data?: T[]; someData: string; }; type KeySet1 = "key1" | "key2"; type KeySet2 = "key3" | "key4"; type DataType1 = { id: string; num: number; }; type DataType2 = { age: number; address: string; }; type KeySet1Record = Record<KeySet1, ObjectDefinationType<DataType1>>; type KeySet2Record = Record<KeySet2, ObjectDefinationType<DataType2>>; type SetStoreType = { set1: KeySet1Record; set2: KeySet2Record; }; const initialData = { myFunction: () => {}, someData: "someData" }; const set1: KeySet1Record = { key1: { ...initialData }, key2: { ...initialData } }; const set2: KeySet2Record = { key3: { ...initialData }, key4: { ...initialData } }; const setStore: SetStoreType = { set1, set2 }; const myFunc = <T extends keyof SetStoreType, K extends keyof SetStoreType[T]>( key: T, subKey: K ) => { // 此处访问属性报类型错误 console.log("I want to access data", setStore[key][subKey].someData); // 此处赋值报类型错误 setStore[key][subKey].myFunction = () => { // 函数逻辑 }; };
报错原因
TS对多层嵌套的泛型索引存在类型收敛缺陷:当使用两层泛型参数分别约束外层key和内层subKey时,TS无法正确关联两个泛型参数的对应关系,会把setStore[key][subKey]的类型推断为不具备已知属性的交叉类型,导致无法正常访问上面定义的myFunction、someData属性。
修复方案
不需要修改原有类型定义,也不需要用全量覆盖对象的绕路写法,两种可直接落地的方案如下:
- 方案1:取出嵌套值后通过类型断言明确类型
const myFunc = <T extends keyof SetStoreType, K extends keyof SetStoreType[T]>( key: T, subKey: K ) => { // 明确嵌套值的类型 const target = setStore[key][subKey] as ObjectDefinationType<DataType1 | DataType2>; // 正常访问属性 console.log("I want to access data", target.someData); // 正常赋值方法 target.myFunction = () => { // 函数逻辑 }; };
- 方案2:优化泛型索引的类型声明,让TS自动收敛类型
const myFunc = <T extends keyof SetStoreType, K extends keyof SetStoreType[T]>( key: T, subKey: K ) => { const store = setStore as Record<T, Record<K, ObjectDefinationType<any>>>; const target = store[key][subKey]; console.log("I want to access data", target.someData); target.myFunction = () => { // 函数逻辑 }; };
两种写法都可以让属性访问和赋值的类型检查正常通过,运行时逻辑和预期完全一致。
内容的提问来源于stack exchange,提问作者Kunal Jain
相关产品推荐
相关产品推荐

