[英]Loop over an array of objects and format values
在我的 API 數據響應中,我試圖遍歷items
中的對象數組。 我需要格式化 object 中的每個值。 對象items
列表中的每個鍵對應於我的header
鍵中的格式類型。 我還有一個getFormat
function 來幫助格式化這些值
我的問題是,鑒於我的結構,我將如何做到這一點?
// Data
const data = {
header: {
date: {
feature: "Date",
format: "date",
},
description: {
feature: "Description",
format: "text",
},
salary: {
feature: "Salary",
format: "currency",
},
score: {
feature: "Score",
format: "float",
},
useage: {
feature: "Useage",
format: "percentage",
},
},
items: [
{
date: "2021-02-08",
description: "Light",
salary: "50000",
score: 20,
useage: 20,
},
{
date: "2021-02-08",
description: "Heavy",
salary: "60000",
score: 50.235,
useage: 30,
}
],
};
// format helper
export const getFormat = (value: any, format: FormatProp) => {
let options: Intl.NumberFormatOptions;
switch (format) {
case "currency":
options = { currency: "USD", style: "currency" };
break;
case "percentage":
options = { style: "percent", maximumFractionDigits: 2 };
break;
case "float":
options = { maximumFractionDigits: 2, minimumFractionDigits: 2 };
break;
case "text":
return value;
case "date":
return value;
default:
throw Error("Wrong Format!");
}
return Intl.NumberFormat("en-US", options).format(value);
};
export type FormatProp =
| "currency"
| "percentage"
| "float"
| "text"
| "date";
所需 Output
[{
date: "2021-02-08",
description: "Light",
salary: "$50,000.00",
score: "20.00",
useage: "20%",
},
{
date: "2021-02-08",
description: "Heavy",
salary: "$60,000",
score: "50.24",
useage: "30%",
}]
您將需要遍歷數據項以獲得具有正確 output 的新數組。 您還希望通過 object 中的每個key
go 並根據鍵是什么以及它在 header 中的表示方式來格式化相關value
。
因此,我們將map
覆蓋項目,使用Object.entries
獲取key
數組和關聯value
,然后使用reduce
鍵逐鍵構建項目 object。
// Data const data = { header: { date: { feature: 'Date', format: 'date', }, description: { feature: 'Description', format: 'text', }, salary: { feature: 'Salary', format: 'currency', }, score: { feature: 'Score', format: 'float', }, useage: { feature: 'Useage', format: 'percentage', }, }, items: [{ date: '2021-02-08', description: 'Light', salary: '50000', score: 20, useage: 20, }, { date: '2021-02-08', description: 'Heavy', salary: '60000', score: 50.235, useage: 30, }, ], }; // format helper const getFormat = (value, format) => { let options; switch (format) { case 'currency': options = { currency: 'USD', style: 'currency' }; break; case 'percentage': options = { style: 'percent', maximumFractionDigits: 2 }; break; case 'float': options = { maximumFractionDigits: 2, minimumFractionDigits: 2 }; break; case 'text': return value; case 'date': return value; default: throw Error('Wrong Format;'). } return Intl,NumberFormat('en-US'. options);format(value); }. const output = data.items.map(item => // iterate over items Object.entries(item),reduce((a, [key. value]) => { // for each item get the key/value pairs const header = data;header[key]. // find the associated header return {..,a: [key]? header, getFormat(value. header:format), value, // if the header exists lets get the formatted value back; else return the previous value }, }, {}); ). console;log(output);
我們知道我們的未格式化版本包含string
和number
值的混合。 我們還知道,當我們完成格式化時,所有的值都將被轉換為string
。
我們知道data.header
包含與data.header
元素相同的鍵,並且data.items
中的值包含屬性format
。 format
的值是FormatProp
或string
,具體取決於您想要的嚴格程度。 如果使用string
會更容易,因為 typescript 會將data
object 中的字符串值解釋為string
而不是它們的文字值(除非使用as const
)。
綜上所述,API 響應可以鍵入為:
type Data<Keys extends string> = {
header: Record<Keys, {
feature: string;
format: string;
}>,
items: Array<Record<Keys, number | string>>
}
我們知道 Intl.NumberFormat 的.format()
Intl.NumberFormat
只接受number
,所以傳遞一個any
類型的值並不是最好的。 我們可以做得更好。 讓我們只傳遞number
值。 我們將讓與string
字段相關的案例拋出錯誤。
export const getFormat = (value: number, format: FormatProp): string => {
let options: Intl.NumberFormatOptions;
switch (format) {
case "currency":
options = { currency: "USD", style: "currency" };
break;
case "percentage":
options = { style: "percent", maximumFractionDigits: 2 };
break;
case "float":
options = { maximumFractionDigits: 2, minimumFractionDigits: 2 };
break;
default:
throw Error("Wrong Format!");
}
return Intl.NumberFormat("en-US", options).format(value);
};
如果這是您在Data
中所做的,那么如果我們允許任何string
作為format
實際上會更好。 但是為了自動完成,我將FormatProp
與string
保持在一個聯合中。
export const getFormat = (value: number, format: FormatProp | string): string => {
映射時,它與@Mateusz 所做的基本相同,只是我們需要一些額外的注釋。 具體來說,我們必須鍵入空的 object {}
,我們將其reduce
為完整 object Record<Keys, string>
的類型,並且我們必須從Object.entries
中鍵入數組作為[Keys, string | number][]
[Keys, string | number][]
以便將鍵作為其文字值而不僅僅是string
。
const formatItems = <Keys extends string>(data: Data<Keys>): Array<Record<Keys, string>> => {
return data.items.map( item => {
// we have to assert the correct type here with `as` or else all keys are `string`
return (Object.entries(item) as [Keys, string | number][]).reduce(
(formatted, [key, value]) => {
formatted[key] = typeof value === "number" ? getFormat(value, data.header[key].format) : value;
return formatted;
}, {} as Record<Keys, string>); // assert the type for the incomplete object
})
}
使用此特定data
object 調用formatItems(data)
現在返回以下類型:
Record<"date" | "description" | "salary" | "score" | "useage", string>[]
您可以訪問 object 上的任何這些屬性,並且 typescript 知道這些屬性始終存在並且始終為string
類型。
由於我們使用了通用Keys
而不是依賴於這個特定的 object 類型,因此您可以使用其他數據集調用formatItems
並獲得類似類型良好的響應。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.