[英]TypeScript: How to cast generic type to another generic type when overloading a function?
我想定義一個從數組創建字典的通用 function。 function 將array
、一個keySelector
和一個可選的valueSelector
作為參數。 如果沒有提供valueSelector
,則 function 回退到標識 function。我希望 Typescript 能夠理解類型V
與T
相同。 相反,編譯器給我錯誤Type 'T' is not assignable to type 'V'
。
export function arrayToDictionary<T, K extends string | number | symbol, V>(
array: T[],
keySelector: (item: T) => K,
valueSelector: (item: T) => V = (item) => item // ERROR Type 'T' is not assignable to type 'V'
): Record<K, V> {
return array.reduce(
(acc, curr) => ({ ...acc, [keySelector(curr)]: valueSelector(curr) }),
{} as Record<K, V>
);
}
這是TypeScript 游樂場的鏈接。
我找到的唯一解決方案是使用any
關鍵字。
valueSelector: (item: T) => V = (item: any) => item
期望的結果如下:
const array = [
{ id: 1, name: "John" },
{ id: 2, name: "Will" },
{ id: 3, name: "Jane" },
];
// dict1 type should be Record<number, {id: number; name: string; }>
const dict1 = arrayToDictionary(array, p => p.id);
// dict2 type should be Record<number, string>
const dict2 = arrayToDictionary(array, p => p.id, p => p.name);
有沒有更好的方法來定義 function 的類型?
您可以將valueSelector
參數的返回類型從簡單的V
放寬到V | T
V | T
,這正是您想要表達的內容,同時為您的泛型V
提供默認類型(如果您不將第三個參數傳遞給函數,它將被推斷為unknown
類型)。
function arrayToDictionary<T, K extends string | number | symbol, V = T>(
array: T[],
keySelector: (item: T) => K,
valueSelector: (item: T) => V | T = item => item
): Record<K, V> {
return array.reduce(
(acc, curr) => ({ ...acc, [keySelector(curr)]: valueSelector(curr) }),
{} as Record<K, V>
);
}
const arr = [1,2,3,4]
const dict1 = arrayToDictionary(arr, n => n.toString() + '!', n => n > 2) //Record<string, boolean>
const dict2 = arrayToDictionary(arr, n => n.toString() + '!') //Record<string, number>
我認為你可以考慮使用function 重載:
function arrayToDictionary<T, K extends string | number | symbol>(
array: T[],
keySelector: (item: T) => K
) : Record<K, K>;
function arrayToDictionary<T, K extends string | number | symbol, V>(
array: T[],
keySelector: (item: T) => K,
valueSelector: (item: T) => V
): Record<K, V>;
function arrayToDictionary<T, K extends string | number | symbol, V>(
array: T[],
keySelector: (item: T) => K,
valueSelector?: (item: T) => V
): Record<K, V> {
return array.reduce(
(acc, curr) => ({ ...acc, [keySelector(curr)]: valueSelector?.(curr)??curr }),
{} as Record<K, V>
);
}
雖然這不能直接解決問題,但它確實提供了關於 function 簽名的明確反饋。 該實現預計只會涵蓋 function 所做的事情,而不管使用哪個簽名來調用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.