【问题标题】:Manipulating array of objects using reduce, correct types are missing使用 reduce 操作对象数组,缺少正确的类型
【发布时间】:2021-03-02 09:34:24
【问题描述】:

使用reduce操作对象数组,缺少正确的类型

我从 API 响应中获取了我需要操作的数组,然后才能在我的节点应用程序中使用它。

这是我已经在我的应用中所做的:

const array = [
  {
    users: {
      'bc1bff64-ecde-4500-b16d-c1d3a37f2558': {
        points: 368,
        user_id: 'bc1bff64-ecde-4500-b16d-c1d3a37f2558',
        period: 6,
        city: 'london'
      },
      '5124be0c-3faf-444d-9e83-b570ca42c772': {
        points: 358,
        user_id: '5124be0c-3faf-444d-9e83-b570ca42c772',
        period: 6,
        city: 'london'
      }
    }
  },
  {
    users: {
      'bc1bff64-ecde-4500-b16d-c1d3a37f2558': {
        points: 368,
        user_id: 'bc1bff64-ecde-4500-b16d-c1d3a37f2558',
        period: 6,
        city: 'paris'
      },
      '5124be0c-3faf-444d-9e83-b570ca42c772': {
        points: 358,
        user_id: '5124be0c-3faf-444d-9e83-b570ca42c772',
        period: 6,
        city: 'paris'
      }
    }
  },
  {
    users: {
      'bc1bff64-ecde-4500-b16d-c1d3a37f2558': {
        points: 0,
        user_id: 'bc1bff64-ecde-4500-b16d-c1d3a37f2558',
        period: 5,
        city: 'london'
      },
      '5124be0c-3faf-444d-9e83-b570ca42c772': {
        points: 0,
        user_id: '5124be0c-3faf-444d-9e83-b570ca42c772',
        period: 5,
        city: 'london'
      }
    }
  },
  {
    users: {
      'bc1bff64-ecde-4500-b16d-c1d3a37f2558': {
        points: 0,
        user_id: 'bc1bff64-ecde-4500-b16d-c1d3a37f2558',
        period: 5,
        city: 'paris'
      },
      '5124be0c-3faf-444d-9e83-b570ca42c772': {
        points: 0,
        user_id: '5124be0c-3faf-444d-9e83-b570ca42c772',
        period: 5,
        city: 'paris'
      }
    }
  }
];

const getPeriodName = (period: number) =>
  ({ 5: 'PERIOD_5_NAME', 6: 'PERIOD_6_NAME' }[period]);
const getCityName = (city: string) =>
  ({ 'london': 'London', 'paris': 'Paris' }[city]);
const getPointsGain = (points: number) => points + 'blabla';

const reduced = array.reduce((acc, { users }) => {
  Object.entries(users)
    .map(([id, { ...all }]) => {
      acc[id] = acc[id] || {
        id, periods: {}
      };
      acc[id].periods[all.period] = acc[id].periods[all.period] || {
        name: getPeriodName(all.period),
        cities: {}
      };
      acc[id].periods[all.period].cities[all.city] = {
        name: getCityName(all.city),
        points: all.points,
        pointsGain: getPointsGain(all.points)
      };
    });
  return acc;
}, {});
const result = Object.values(reduced);
console.log('result', result);

问题是 reduced 是类型 {} 空对象而不是正确的完整类型

“正确”类型的示例

我想以正确的类型结束这个数组:

[
  {
    "id": "bc1bff64-ecde-4500-b16d-c1d3a37f2558",
    "periods": {
      "5": {
        "name": "PERIOD_5_NAME",
        "cities": {
          "london": {
            "name": "London",
            "points": 0,
            "pointsGain": "0blabla"
          },
          "paris": {
            "name": "Paris",
            "points": 0,
            "pointsGain": "0blabla"
          }
        }
      },
      "6": {
        "name": "PERIOD_6_NAME",
        "cities": {
          "london": {
            "name": "London",
            "points": 368,
            "pointsGain": "368blabla"
          },
          "paris": {
            "name": "Paris",
            "points": 368,
            "pointsGain": "368blabla"
          }
        }
      }
    }
  },
  {
    "id": "5124be0c-3faf-444d-9e83-b570ca42c772",
    "periods": {
      "5": {
        "name": "PERIOD_5_NAME",
        "cities": {
          "london": {
            "name": "London",
            "points": 0,
            "pointsGain": "0blabla"
          },
          "paris": {
            "name": "Paris",
            "points": 0,
            "pointsGain": "0blabla"
          }
        }
      },
      "6": {
        "name": "PERIOD_6_NAME",
        "cities": {
          "london": {
            "name": "London",
            "points": 358,
            "pointsGain": "358blabla"
          },
          "paris": {
            "name": "Paris",
            "points": 358,
            "pointsGain": "358blabla"
          }
        }
      }
    }
  }
]

【问题讨论】:

    标签: javascript arrays typescript reduce


    【解决方案1】:

    当使用reduce 合并到单个对象中时,即使在纯 JavaScript 中,代码也可能有些冗长。可以说是not semantically appropriate either。使用 TypeScript,情况更糟,因为您必须键入在每次迭代中传递的累加器。

    考虑在外部创建对象,并列出其类型,然后使用for..of 遍历数组。以下编译没有 TS 错误:

    type Periods = {
      [period: number]: {
        name: string;
        cities: {
          [city: string]: {
            name: string;
            points: number;
            pointsGain: string;
          }
        }
      }
    };
    const acc: {
      [id: string]: { id: string, periods: Periods }
    } = {};
    for (const { users } of array) {
      Object.entries(users)
        .forEach(([id, { ...all }]) => {
          acc[id] = acc[id] || {
            id, periods: {}
          };
          acc[id].periods[all.period] = acc[id].periods[all.period] || {
            name: getPeriodName(all.period),
            cities: {}
          };
          acc[id].periods[all.period].cities[all.city] = {
            name: getCityName(all.city),
            points: all.points,
            pointsGain: getPointsGain(all.points)
          };
        });
    }
    const result = Object.values(acc);
    

    请注意,由于您在Object.entries 之后执行副作用,因此您应该使用forEach,而不是.map。 (仅当您需要通过转换初始数组的所有元素来创建新数组时才使用.map

    【讨论】:

    • 我想过写界面,但问题是当我在那里使用真实数据时不仅仅是一个 points 键,所以如果我需要更新一些东西,我必须手动更改界面或类型理想的。有没有办法使用自动生成的类型?
    • 我使用的是type,而不是接口。不,当您需要在 TypeScript 中重新组织数据时,除了详尽地指定新数据结构的类型之外,通常没有其他选择。
    • 为什么?例如,如果您这样做 hastebin.net/zurofacuxy.js 也正在重新组织数据,那么您为什么要将 number[] 分配给 array2(如果它已经存在)。
    • 对于像这样的非常微不足道的操作,是的,TypeScript 可以自动推断它 - 但对于几乎任何更复杂的东西,如果不是单个转换,则无法自动推断使用内置的 JavaScript 函数,或者如果执行的过程是非函数式的(TS 最适合函数式范例,但大量代码使用非函数式范例最有意义)
    • 我想你可以获得 partway 的一种方法是运行应用转换的 JavaScript 代码,然后将生成的对象复制到 TypeScript IDE,然后复制 IDE 的该代码的自动检测类型。但是具有动态属性名称的对象必须手动修复(例如这里的ids)。
    猜你喜欢
    • 1970-01-01
    • 2021-12-02
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    • 2021-12-17
    • 1970-01-01
    • 2022-11-09
    相关资源
    最近更新 更多