我想写一个泛型函数,它可以创建一个对象的Map,其中键是对象本身的属性,因此可以根据它们的一个属性的值对它们进行分组。
最后我写了下面的代码:
type PartialRecord<K extends keyof any, T> = {
[P in K]?: T;
};
const innerMap = <T, K extends keyof any>(
array: T[], customKey: keyof T
): PartialRecord<K, T> => {
const innerMap: PartialRecord<K, T> = {};
for (let i = 0; i < array.length; ++i) {
innerMap[array[i][customKey] as K] = array[i];
}
return innerMap;
}
}
字符串
它给出了错误:Conversion of type 'T[keyof T]' to type 'K' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first
的。
所以你会得到:innerMap[array[i][customKey] as unknown as K
,这(双重)违背了打字的目的。
它应该做的是:
export class CuteKitty {
constructor(readonly furColor: string, readonly eyeColor: string) {}
}
const redKittyBlueEyes = new CuteKitty('red', 'blue');
const redKittyRedEyes = new CuteKitty('red', 'red');
const whiteKittyRedEyes = new CuteKitty('white', 'red');
const furColorMap = innerMap([redKittyBlueEyes, redKittyRedEyes, whiteKittyRedEyes], 'furColor');
// Result: {
// red: [redKittyBlueEyes, redKittyRedEyes];
// white: [whiteKittyRedEyes];
// }
const eyeColorMap = innerMap([redKittyBlueEyes, redKittyRedEyes, whiteKittyRedEyes], 'eyeColor');
// Result: {
// blue: [redKittyBlueEyes];
// red: [redKittyRedEyes, whiteKittyRedEyes];
// }
型
如果不对innerMap[array[i][customKey]] as unknown as K
进行强制转换,我如何确保array[i][customKey]
是一个可用于索引的类型(特别是我替换K
的类型)?
1条答案
按热度按时间vmpqdwk31#
一路沿着学到了一些东西,所以我调整了几次我的答案。最后的解决方案是最有用的imo。
1.原始答案
找到了一个解决方案,而不必使用肮脏的修复铸造“作为未知的K”。
我创建了这些自定义类型:
字符串
然后我调整了上面的代码如下:
型
现在你可以加入一个对象数组,和一个属性的字符串名称,它会在一个map中根据该属性对这些对象进行分组。
2.答案03-10-2022
为基本相同的事情编写更简单的代码。
TRecordKey
和TRecurringRecord
,它只是声明键应该是字符串。这是处理“两种类型都不与另一种类型充分重叠”警告的简单得多的方法。(如果对象具有数字/符号属性,则不起作用)。型
3.答案01-08-2023
T[K]
而不是K
)。K
的强类型,因为我个人通常只希望键是number | string | symbol
类型,而不是对象。TIndexable
类型,只使用Record<any, any>
,这将允许任何对象。型
T[K] extends Record<any, any> ? never : (keyof T & TRecordKey)
意味着如果键K
处的属性的类型是对象,则never
也可以是这种情况,因此当您尝试将该类型的属性的名称传递到函数中时,它会生成错误。否则,K
必须是T
的键,并且还必须是string
、number
或symbol
。