簡體   English   中英

循環對象數組和格式值

[英]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);

鍵入響應

我們知道我們的未格式化版本包含stringnumber值的混合。 我們還知道,當我們完成格式化時,所有的值都將被轉換為string

我們知道data.header包含與data.header元素相同的鍵,並且data.items中的值包含屬性format format的值是FormatPropstring ,具體取決於您想要的嚴格程度。 如果使用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>>
}

鍵入 Map 函數

我們知道 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實際上會更好。 但是為了自動完成,我將FormatPropstring保持在一個聯合中。

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.

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