如果从对象中取一部分属性,请问有什么现成的轮子 - CNode技术社区

如果从对象中取一部分属性,请问有什么现成的轮子
发布于 7 年前 作者 DiamondYuan 3216 次浏览 来自 问答

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

回到顶部

AltStyle によって変換されたページ (->オリジナル) /