我有这些接口:
export interface QueryObject {
id: ID;
path: string[];
filters: Filters;
}
export interface Filters {
state: string;
localeID: string;
role: string;
}
并尝试提出一个功能编程解决方案,以便仅将tmp对象中存在的并具有值的属性复制到现有数据模型中。现在,..显然这是行不通的。 Filters
将被完全覆盖,同时丢失属性localeID
和role
。
let queryObject: QueryObject;
let filters: Filters = { state: 'GB'}; // this obviously gives an error on Interface implementation
queryObject.filters = filters;
现在,我正在获取原始对象,遍历该属性并用更新后的值覆盖它。
const queryObject: QueryObject = _.cloneDeep(this.queryObject);
queryObject.filters.state = state; // 'GB'
this.portareService.update(queryObject, this.portareQuery.getActiveId());
使用Object.assign或传播...
这样的解决方案来解决此问题将非常好:
{
return ...createQueryObject, updatedQueryObject
}
我知道如何使用一个或多个循环使用函数,但是正在寻找一种功能编程方法。
答案 0 :(得分:2)
您可以为concat
和QueryObject
都实现Filters
方法。在concat
中,定义要使用的“合并逻辑”。 QueryObject
在内部调用Filters
'concat方法。
在concat
方法中,您可以使用传播语法或任何其他逻辑来确保创建新对象,并且不对任何内容进行突变。
通过添加empty
构造函数,您可以轻松地开始在reduce
或其他自动合并中使用那些串联器。
我发现this blog post on Semigroups by Tom Harding很有启发性。 This post about Monoids中包含有关empty
部分的一些信息。
const QueryObject = ({id = null, path = null, filters = Filters.empty() })=> ({
id,
path,
filters,
concat: other => QueryObject({
id: other.id || id,
path: other.path || path,
filters: filters.concat(other.filters)
}),
toString: () => `QueryObject(${id}, ${path}, ${filters.toString()})`
});
QueryObject.empty = () => QueryObject({});
QueryObject.merge = (x, y) => x.concat(y);
const Filters = ({ state = null, localeID = null, role = null }) => ({
state,
localeID,
role,
concat: other => Filters({
state: other.state || state,
localeID: other.localeID || localeID,
role: other.role || role
}),
toString: () => `Filters(${state}, ${localeID}, ${role})`
});
Filters.empty = () => Filters({});
Filters.merge = (x, y) => x.concat(y);
const userFilter = Filters({ role: "User" });
const gbFilter = Filters({ localeID: "GB" });
const filterSettings = [userFilter, gbFilter];
const mergedFilter = filterSettings.reduce(Filters.merge, Filters.empty());
console.log(
"Merged Filter:",
mergedFilter.toString()
);
// Some base query
const accountQuery = QueryObject({ id: "CUSTOM_Q_1", path: "/accounts" });
// Derived queries
const userQuery = accountQuery.concat(QueryObject({ filters: userFilter }));
const gbQuery = accountQuery.concat(QueryObject({ filters: gbFilter }));
console.log(
"User Query:",
userQuery.toString()
);
console.log(
"Brittish Users Query",
userQuery.concat(gbQuery).toString()
);
编辑: 当然,如果没有“理论”,那就还有更通用的方法:
const uniques = xs => Array.from(new Set(xs));
const nullMergeStrategy = (obj1, obj2) =>
uniques(
Object.keys(obj1)
.concat(Object.keys(obj2))
).reduce(
(acc, k) => Object.assign(acc, { [k]: obj2[k] || obj1[k] }),
{}
);
const Filter = ({ state = null, localeID = null, role = null }) =>
({ state, localeID, role });
const userFilter = Filter({ role: "User" });
const gbFilter = Filter({ localeID: "GB" });
console.log(
nullMergeStrategy(userFilter, gbFilter)
)