[英]Typescript reduce a list of objects to an object with a different shape
如果沒有一些笨拙的類型斷言,我這輩子都無法弄清楚如何修改 reduce 的返回值。 例如:
const list: Array<Record<string, string | number>> = [
{
resourceName: "a",
usage: 20
},
{
resourceName: "b",
usage: 50
}
];
const toMap = list.reduce(
(acc, item) => ({
...acc,
[item.resourceName]: item.usage
}),
{}
);
toMap
的類型為Record<string, string | number>
Record<string, string | number>
作為list
的形狀為Array<Record<string, string | number>>
Array<Record<string, string | number>>
但我不關心我的輸入列表的形狀,我關心我的 output object 的形狀,即Record<string, number>
。
在這個例子中,我可以在末尾添加一個類型斷言以獲得正確的類型,但有時list
類型和 output 類型不匹配,並且必須使用as unknown as X
來進行像reduce
這樣常見的操作似乎不正確至少可以說。
您確實需要關心輸入列表的形狀,至少在您希望編譯器理解item.usage
是一個number
而不是string | number
的范圍內。 string | number
。 如果將list
注釋為Array<Record<string, string | number>>
Array<Record<string, string | number>>
,然后你明確告訴編譯器忘記關於list
的所有內容,除了它是一個屬性類型為string | number
的對象數組。 string | number
。 在此之后, reduce()
與item.usage
的任何使用都必然涉及string | number
string | number
,除非您使用類型斷言之類的東西來向編譯器返回您之前丟棄的一些信息。
在這種情況下,我建議不要使用list
的類型注釋,讓編譯器從初始化值推斷其類型:
const list = [
{
resourceName: "a",
usage: 20
},
{
resourceName: "b",
usage: 50
}
];
/* const list: {
resourceName: string;
usage: number;
}[] */
您可以看到,這個推斷的類型是一個對象數組,其resourceName
屬性為string
類型,而usage
屬性為number
類型。 對於您的目的,這是一個更有用的list
分類。
現在你想使用reduce()
。 這里的問題是您傳入了一個初始累加器,它是一個空的 object {}
。 留給它自己的設備,編譯器將推斷{}
作為這個初始累加器的類型,並由此推斷reduce()
調用簽名上的泛型類型參數也是{}
類型,最后得出返回值也是{}
類型。 (有時編譯器的類型推斷會為您提供所需的類型,而有時則不會。這就是啟發式算法的方式。)如果您希望發生其他事情,則需要防止這種推斷。
一種方法是提前聲明初始累加器,其類型顯式注釋為您想要的:
const init: Record<string, number> = {};
const toMap = list.reduce(
(acc, item) => ({
...acc,
[item.resourceName]: item.usage
}),
init
);
// const toMap: Record<string, number>
現在編譯器不需要推斷init
的類型; 並且reduce()
中的類型參數被推斷為Record<string, number>
,因此toMap
也是Record<string, number>
。
另一種方法是在調用reduce()
時手動指定類型參數。 這可以防止類型參數的推斷,並允許編譯器根據上下文推斷初始累加器的類型:
const toMap = list.reduce<Record<string, number>>(
(acc, item) => ({
...acc,
[item.resourceName]: item.usage
}),
{}
);
// const toMap: Record<string, number>
無論哪種方式都應該適合你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.