[英]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.