typescript - 根据枚举值过滤数据 - 打字稿
问题描述
我有一个带有两个键的枚举。我想根据枚举的键过滤我的数据并返回一个对象。
enum ArchiveStatus {
Current = 0,
Archive = 1,
}
const data = [{name:'A', Archive_Status: 0}, {name: 'B', Archive_Status: 0}, {name: 'C', Archive_Status: 1}, {name: 'D', Archive_Status: 1}];
const filteredData = {
Current: data.filter(item => item.Archive_Status === ArchiveStatus.Current),
Archive: data.filter(item => item.Archive_Status === ArchiveStatus.Archive)
}
console.log(filteredData)
预期结果:
{ "Current": [ { "name": "A", "Archive_Status": 0 }, { "name": "B", "Archive_Status": 0 } ], "Archive": [ { "name": "C", "Archive_Status": 1 }, { "name": "D", "Archive_Status": 1 } ] }
我能够以这种方式实现它。但我想从枚举动态创建新属性并根据 Archive_Status 过滤数据并将其添加到此对象。例如,如果枚举有 10 个属性,我不想每次都在对象中输入键名。请指教。
解决方案
获取枚举名称
如果要根据枚举动态创建对象中的所有键,则需要获取枚举键。没有内置的方法可以做到这一点 - 问题是 TypeScript 在键和值之间生成双重绑定以确保两者的唯一性。
enum ArchiveStatus {
Current = 0,
Archive = 1,
}
有效地编译为:
ArchiveStatus = {
"Current": 0,
"Archive": 1,
0: "Current",
1: "Archive",
}
但是,如果枚举值都是数字,您可以将它们过滤掉,Object.values(ArchiveStatus).filter(x => typeof x !== "number")
只留下名称:
enum ArchiveStatus {
Current = 0,
Archive = 1
}
//create a type for the names for type safety later
type ArchiveStatusName = keyof typeof ArchiveStatus;
const enumNames = Object.values(ArchiveStatus)
.filter(x => typeof x !== "number") as ArchiveStatusName[]; //type assertion needed as compiler cannot determine this is safe
JavaScript 演示:
const ArchiveStatus = {
"Current": 0,
"Archive": 1,
0: "Current",
1: "Archive",
}
const enumNames = Object.values(ArchiveStatus)
.filter(x => typeof x !== "number");
console.log(enumNames);
泛化过滤
现在过滤器调用可以概括为使用枚举的任何名称来调用它们。这就是我们想要做的,因为我们已经有了名字。
使用柯里化函数很容易做到这一点。这是重构以使用它的代码:
//formalised the interface for the data
interface DataItem {
name: string;
Archive_Status: ArchiveStatus;
}
//generalised filter function for each status
const statusFilter = (status: ArchiveStatus) => (item: DataItem) : boolean =>
item.Archive_Status === status;
//using the filters
const filteredData = {
Current: data.filter(statusFilter(ArchiveStatus.Current)),
Archive: data.filter(statusFilter(ArchiveStatus.Archive))
}
生成具有状态和过滤数据的对象
使用上面的工具,只需将它们放在一起即可。我们可以遍历所有的enumNames
并创建一个对象
- 每个名字作为一个键
- 以该状态作为值过滤的数据
JavaScript 提供了一种创建对象的便捷方法,称为Object.fromEntries
- 它采用一对数组。对于 TypeScript,它是一个类型为 的元组数组[key: string, value: any]
。我们可以创建这样一个结构,然后将其Object.fromEntries
用于为我们生成对象:
//create key-value pairs for the dynamically created object
const pairs = enumNames.map(name => [
name,
data.filter(statusFilter(ArchiveStatus[name]))
]);
const filteredData = Object.fromEntries(pairs);
过滤掉没有任何数据的键
如果需要,我们可以跳过值没有数据的任何键。我们可以删除第二项是空数组的对:
//create key-value pairs for the dynamically created object
const pairs = enumNames.map(name => [
name,
data.filter(statusFilter(ArchiveStatus[name]))
])
.filter(([, value]) => value.length > 0); // remove any pair where the value is an empty array
const filteredData = Object.fromEntries(pairs);
推荐阅读
- google-cloud-firestore - Cloud Firestore 上的写入速度
- powershell - Powershell - 仅当状态码 -ne 200 时,我将如何从 foreach 循环中返回 appname?
- r - 在增加和减少列的两个条件下对 r 中的数据框进行排序
- xml - 使用 Many2one 字段编写域
- masstransit - MassTransit Bus.Publish 调用 SendObserver
- cordova - fcm getToken 进入无限循环
- android - Android webview onShowFileChooser onReceiveValue 没有效果
- jquery - 如果单击关闭一个,如何关闭已打开的其他元素
- javascript - 如果 DOM 上不存在 FormControl,Angular 4+ FormGroup 返回 INVALID
- javascript - 从 Gist 调用函数