ⓘ
在后端开发当中,我们可能需要处理如下的情况,数据库Schema定义了一些数据字段,但API返回的数据,可能需要去掉一些字段,或者又要临时多出一些字段返回给前端,如何能简单优化快捷地处理这种情况呢?
举例来说,数据库定义结构如下,Demo数据对象:
{
id: ObjectId;
name: string;
value1: string;
value2: string;
created: Date;
updated: Date;
}
现在后端 API 返回数据,可能出现两种情况:
- 减少一些内部字段输出给前端,例如上述的 created, updated字段,是内部的日志时间戳使用,我们并不想给前端,那么需要去掉多余的字段。
- 因为业务需要,临时在原来的字段基础上,再增加一些额外的信息输出。
对于上述的两种情况,我们可以考虑单独定义不同的 Response 数据结构来作为输出响应。这种方法,比较繁琐,例如我们有5个API,每个API在Demo的基础上可能都有一些不同的输出要求,如果分别定义的话,就有5个冗余的类定义出来,当然我们可以使用继承来实现,但也是非常繁琐,代码量比较大的。对于简单的差异化字段数量处理,我们可以使用对象解构技术来去掉不需要的字段,使用交叉类型来增加额外的字段。
对象解构
如果我们需要减少字段的输出,方法有几种,一种是在数据库查询的时候,使用投影技术,即不输出某些不需要的字段,但是很有可能数据的查询是其他模块处理的,我们无法使用投影技术。
以Demo对象为例,如果我们只想返回如下的数据解构:
{
id: ObjectId;
name: string;
value1: string;
value2: string;
}
我们可以使用对象解构技术,快速过滤不需要的字段: const { field1, field2, rest } = dbValue;
例如以Mongodb查询结果返回为例,下面的代码就能返回上述去掉 id, created, update 的精简信息了:
const list = this.demoRepository.find(condition, {}, {});
const ret = list.map( value => {
const { _id, created, updated, rest } = (value as any).toObject();
return rest;
});
return ret;
交叉类型
如果我们需要临时在现有数据DTO/POJO/DAO对象的基础上,增加一些额外的字段,又不想单独定义额外的DTO/POJO/DAO对象类,可以考虑使用交叉类型来实现。
例如:type TempDto = exist_dto & { [key: string]: object }
举例子来说,如果我们希望返回类似Demo的数据(多了address):
{
id: ObjectId;
name: string;
value1: string;
value2: string;
created: Date;
updated: Date;
address: string;
list: Array<string>;
}
我们可以用下面的方法来处理:
type Demo = {
id: string;
name: string;
value1: string;
value2: string;
created: Date;
updated: Date;
};
const demo: Demo = {
id: "3B986461-45F9-E993-4785-01FA7360ED4B",
name: "John Doe",
value1: "Value 1",
value2: "Value 2",
created: new Date(),
updated: new Date(),
};
const extendDemo : DemoData & {
address: string,
list: Array<string>,
} = {
...demo,
"address": "aaaa",
list: ["Item 1", "Item 2", "Item 3"],
}
console.log(extendDemo);