如果从对象中取一部分属性,请问有什么现成的轮子
lodash 有 pick 这个方法
var object = { 'a': 1, 'b': '2', 'c': 3 };
_.pick(object, ['a', 'c']);
// => { 'a': 1, 'c': 3 }
但是 object 如果是一个嵌套的对象的话,就要写很多代码。 我自己写了一个 deeppick 的轮子。
const api: OpenAPIObject = {
openapi: "3.0.1",
info: {
version: "1.0",
title: "test-rest",
description: "swagger3.0.1 api docs",
},
paths: {
"api/v1/cases": {
get: {
tags: ["case-controller"],
summary: "获取病历列表",
parameters: [
{
name: "department_id",
in: "query",
description: "科室ID",
required: false,
schema: {
type: "integer",
format: "int32",
},
},
{
name: "patient_name",
in: "query",
description: "姓名",
required: false,
schema: {
type: "string",
},
},
],
},
},
},
};
const objectPicker = {
paths: new MapPicker({
get: {
summary: true,
parameters: new ArrayPicker({
in: true,
required: true,
}),
},
}),
};
const expectResult = {
paths: {
"api/v1/cases": {
get: {
summary: "获取病历列表",
parameters: [
{ in: "query", required: false },
{ in: "query", required: false },
],
},
},
},
};
expect(deepPick(api, objectPicker)).toEqual(expectResult);
函数效果如上。 虽然我自己写好了,但是我觉得应该前人已经造过现成的轮子了。请问有人见过类似的轮子吗?
5 回复
import { plainToClass, Type, Exclude, Expose } from "class-transformer";
import "reflect-metadata";
const api = {
openapi: "3.0.1",
info: {
version: "1.0",
title: "test-rest",
description: "swagger3.0.1 api docs",
},
paths: {
"api/v1/cases": {
get: {
tags: ["case-controller"],
summary: "获取病历列表",
parameters: [
{
name: "department_id",
in: "query",
description: "科室ID",
required: false,
schema: {
type: "integer",
format: "int32",
},
},
{
name: "patient_name",
in: "query",
description: "姓名",
required: false,
schema: {
type: "string",
},
},
],
},
},
},
};
@Exclude()
class Parameters {
@Expose()
in: string;
@Expose()
required: boolean;
}
@Exclude()
class Get {
@Expose()
summary: string;
@Expose()
@Type(() => Parameters)
parameters: Parameters[];
}
@Exclude()
class Api {
@Expose()
@Type(() => Get)
get: Get;
}
@Exclude()
class Paths {
@Expose()
@Type(() => Api)
['api/v1/cases']: Api;
}
@Exclude()
class Template {
@Expose()
@Type(() => Paths)
paths: Paths;
}
var json = plainToClass(Template, api);
console.log(JSON.stringify(json));
用 class-transformer 得定义类型,比较麻烦,如果不用 ts, 使用 ramda mergeDeep 相关的操作符 应该只需要写 7-8 行
@yviscool 有些情况下map的key是未知的,例如 api/v1/cases 只是举个例子,并不知道有多少API。后来我自己写了一个
export function deepPick(origin: any, keys: Picker) {
if (!origin) {
return undefined;
}
const result: any = {};
Object.keys(keys).forEach((o: string) => {
const valuePicker = keys[o];
let pickResult: any = {};
const originValue = origin[o];
if (!originValue) {
return;
}
if (valuePicker === true) {
pickResult = origin[o];
} else if (valuePicker instanceof MapPicker) {
valuePicker.filter(originValue).forEach((subKey: string) => {
pickResult[subKey] = deepPick(
originValue[subKey],
valuePicker.getPicker(),
);
});
} else if (valuePicker instanceof ArrayPicker) {
pickResult = valuePicker
.filter(originValue)
.map((subObject) => deepPick(subObject, valuePicker.getPicker()));
} else if (valuePicker instanceof Object) {
pickResult = deepPick(origin[o], valuePicker);
}
result[o] = pickResult;
});
return result;
}
export interface Picker {
[key: string]: MapPicker | ArrayPicker | true | Picker;
}
临时写的,暂时够用,测试也没补全。
@DiamondYuan key未知,那么这个库做不到(只能把所有属性都写上)。等等看别人有没什么高招
递归判断就可以了吧。
ECMA-262的一个处于Stage1的草案未来可能会很好解决这个问题: https://github.com/tc39/proposal-optional-chaining/blob/master/README.md