我在尝试索引嵌套对象时遇到了TypeScript问题(7053): Element implicitly has an 'any' type because expression of type X can't be used to index type Y
。TypeScript似乎无法正确建立父键和子键之间的连接,如TheTypeKeysCombined
甚至AllowedKeySubkeyPairs
中定义的那样。.split()
方法的返回值有一些问题,因为手动输入父键和子键可以工作。但我不知道我错过了什么。
构建体TheTypeKeysCombined
例如'second.secondThird'
需要保持这种格式,然后使用.split()
方法只是一个想法,当TheTypeKeysCombined
传递时提取父键和子键。
TypeScript playground示例。
const nestedConstObj = {
first: {
firstFirst: 'firstFirstVal',
},
second: {
secondFirst: 'secondFirstVal',
secondSecond: 'secondSecondVal',
secondThird: 'secondThirdVal',
secondFourth: 'secondFourthVal',
},
third: {
thirdFirst: 'thirdFirstVal',
thirdSecond: 'thirdFirstVal',
},
} as const;
type TheType = typeof nestedConstObj;
type TheTypeKeys = {[K in keyof TheType]: keyof TheType[K]};
type TheTypeKeysCombined = {[K in keyof TheTypeKeys]: `${K}.${TheTypeKeys[K]}`}[keyof TheTypeKeys];
// type TheTypeKeysCombined = "first.firstFirst" | "second.secondFirst" | "second.secondSecond" | "second.secondThird" | "second.secondFourth" | "third.thirdFirst" | "third.thirdSecond"
// Let's say we get something like this:
const myQuery : TheTypeKeysCombined = 'second.secondThird';
// Try #1 --- THE ISSUE ---
const [keyLvl1_1, keyLvl1_2] = myQuery.split('.');
const myVal1 = nestedConstObj[keyLvl1_1][keyLvl1_2];
// -> Element implicitly has an 'any' type because expression of type 'string' can't be used to index type ...
// Try manually
const [keyLvlM_1, keyLvlM_2] : AllowedKeySubkeyPairs = ['second', 'secondThird'];
const myValM = nestedConstObj[keyLvlM_1][keyLvlM_2];
// -> Works, but I need rather with `myQuery.split('.')`
// Try #2
const [keyLvl2_1, keyLvl2_2] = myQuery.split('.');
const myVal2 = nestedConstObj[keyLvl2_1 as keyof TheType][keyLvl2_2 as keyof TheType[keyof TheType]];
// -> Works but `myVal2` is of type 'never'
// Try #3
const [keyLvl3_1, keyLvl3_2] = myQuery.split('.') as [keyof TheType, keyof TheType[keyof TheType]];
const myVal3 = nestedConstObj[keyLvl3_1][keyLvl3_2];
// -> Works but as well, the `myVal3` is of type 'never', becaue `keyLvl3_2` is of type 'never'
// Try #4
type AllowedKeySubkeyPairs = {[K in keyof TheType]: {[K2 in keyof TheType[K]] : [K, K2]}[keyof TheType[K]]}[keyof TheType];
// type AllowedKeySubkey = ["first", "firstFirst"] | ["second", "secondFirst"] | ["second", "secondSecond"] | ["second", "secondThird"] | ["second", "secondFourth"] | ["third", "thirdFirst"] | [...]
const [keyLvl4_1, keyLvl4_2] = myQuery.split('.') as AllowedKeySubkeyPairs;
const myVal4 = nestedConstObj[keyLvl4_1][keyLvl4_2];
// -> Element implicitly has an 'any' type because expression of type ... can't be used to index type ...
1条答案
按热度按时间8ulbf1ek1#
String.prototype.split()
无论什么都返回string[]
,这就是为什么仅仅使用它,我们将无法得到正确的推断。作为一种选择,我们可以编写一个泛型类型
Split
,它将接受字符串和分隔符,并返回一个文本元组。基本上,它是split
的类型版本:说明:
我们需要检查
Str
是否是任何字符串。在这种情况下,没有必要继续下去,因为它不是一个文字字符串:string extends Str
。接下来,我们检查
Str
是否为空,这也阻止了我们继续:'' extends Str
。否则,我们使用推断将
Str
拆分为T
,即Del
之前的部分和U
,即Del
之后的部分。如果这是真的,那么我们将T
放入一个元组中,并递归地调用Split
以获取Str
的其余部分,即U
。如果我们不能推断出T
和U
,这意味着我们不能再除法了,因此我们只返回[Str]
。我们需要创建一个使用上面类型的函数:
不幸的是,我们需要使用Assert,因为
split
返回string[]
。Playground