簡體   English   中英

TypeScript:重載 function 時如何將泛型轉換為另一個泛型?

[英]TypeScript: How to cast generic type to another generic type when overloading a function?

我想定義一個從數組創建字典的通用 function。 function 將array 、一個keySelector和一個可選的valueSelector作為參數。 如果沒有提供valueSelector ,則 function 回退到標識 function。我希望 Typescript 能夠理解類型VT相同。 相反,編譯器給我錯誤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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM