使用 reduce 操作对象数组,缺少正确的类型
Posted
技术标签:
【中文标题】使用 reduce 操作对象数组,缺少正确的类型【英文标题】:Manipulating array of objects using reduce, correct types are missing 【发布时间】: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"
]
【问题讨论】:
【参考方案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 的该代码的自动检测类型。但是具有动态属性名称的对象必须手动修复(例如这里的id
s)。以上是关于使用 reduce 操作对象数组,缺少正确的类型的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 基于reduce方法实现数组内对象的同属性运算
Redux 能够将字符设置为数组,但是删除操作似乎没有到达 reducer