TypeScript动态类型声明错误修复技术求助
Let's break down what's going wrong with your function and fix both errors step by step.
Understanding the Issues
Your code aims to create a function that takes a two-element array (a top-level key of a, plus a second-level key of that property) to access nested values. The problems stem from how you structured your generics:
Error 1:
Type 'keyof D' cannot be used to index type '{ a: string; b: string; c: { k: string; }; }[K]'- You defined
Das a separate generic extendingObjType[K], but TypeScript can't track the direct relationship betweenDandObjType[K]whenKis a union type. This meanskeyof Dmight not be valid for all possible types inObjType[K], so TypeScript blocks the index operation to avoid unsafe access.
- You defined
Error 2:
Type "k" is not assignable to type 'number | "toString" | ...'- When you pass
['a', 'k'],Kis inferred as"a", soObjType[K]isstring. Thekeyof stringincludes all string methods (liketoString) and numeric indices—"k"isn't part of that set, hence the error. Worse, your original generic setup didn't prevent this invalid call from being allowed in the first place.
- When you pass
The Fix
We can simplify the generics to directly link the second argument's type to the first argument's corresponding property. Here's the corrected code:
const a = { a: 'value 1', b: 'value 2', c: { k: 'value 3' } }; type ObjType = typeof a; // Simplify generics: only bind K, derive the second argument's type from ObjType[K] function funArray<K extends keyof ObjType>(arg: [K, keyof ObjType[K]]) { const oneLvl = a[arg[0]]; const secondLvl = oneLvl[arg[1]]; // No more indexing error! console.log(secondLvl); } funArray(['c', 'k']); // Works as expected // funArray(['a', 'k']); // Now throws a helpful error (correct behavior: 'k' isn't a valid key for string)
Why This Works
- Eliminates redundant generics: By removing
D, we directly tie the second argument's type tokeyof ObjType[K]—TypeScript now knows exactly which keys are valid for the property selected byK. - Fixes indexing safety:
oneLvlis typed asObjType[K], andarg[1]is typed askeyof ObjType[K], so indexing is guaranteed to be valid. - Blocks invalid calls: The function now correctly rejects calls like
funArray(['a', 'k'])because"k"isn't a valid key for a string type—this is a good thing, since accessinga.a.kwould be a runtime error anyway.
Optional: Restrict to Nested Object Properties
If you only want to allow calling the function with top-level keys that point to objects (not strings), you can add a conditional type to narrow down valid K values:
// Only allow K where ObjType[K] is an object type ObjectKeys<T> = { [K in keyof T]: T[K] extends object ? K : never }[keyof T]; function funArray<K extends ObjectKeys<ObjType>>(arg: [K, keyof ObjType[K]]) { const oneLvl = a[arg[0]]; const secondLvl = oneLvl[arg[1]]; console.log(secondLvl); } funArray(['c', 'k']); // Still works // funArray(['a', 'k']); // Throws an error immediately (since 'a' isn't an ObjectKey of ObjType)
This version makes the function even stricter, ensuring you can only pass keys that lead to nested objects.
内容的提问来源于stack exchange,提问作者Andriy Bek

