New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deep functionality for omit #723
Comments
We don't support deep omitting but can do deep partial matches of properties to omit because |
For |
... would be super awesome. |
Why is that, @jdalton, it's surely useful. |
Nothing against it. Just waiting for a bit more user demand for the feature. |
I needed something like this, too, so I came up with the following: function omitDeep(collection, excludeKeys) {
function omitFn(value) {
if (value && typeof value === 'object') {
excludeKeys.forEach((key) => {
delete value[key];
});
}
}
return _.cloneDeepWith(collection, omitFn);
} It can certainly be made to be more generic and I'm sure there are optimizations that could be done here, but it worked for me and got rid of my annoying "Maximum call stack size exceeded" error when doing the same thing recursively myself. |
i've searched for that, vote from me |
Don't forget to vote with reactions as it helps us sort by popularity. |
Would love for both, |
BTW, this one is the most popular issue by now... Would it be worth putting it onto the roadmap? |
surely a good feature to be |
agreed! would be awesome and incredibly useful |
Thanks for the show of support for this feature! |
I would love to give it a try |
@avivr The pull request contributing guide is a good place to start. |
Any chance for an array syntax for deep omit? var o = {
id: 1,
value: "test",
child: {
id: 2,
childValue: "test"
}
}
// current way to handle computed key names
// let cv="childValue";
// _.omit(o, `child.${cv}`)
_.omit(o, ["child", "childValue"]); For same reasons |
The |
@jdalton how come? Is there a replacement? |
Omit requires grabbing all possible properties (inherited, own, non-enumerable, symbols, etc.) and then filtering out properties. This is overly complicated and gets worse with deep functionality. It's better to pick the properties you want or simply delete the rogue ones. |
Lodash giveth, lodash taketh away :) |
FTFY. |
(but not deep) |
In my case, I guess I'll have to clone the object, then somehow delete the rogue keys as mentioned above, then get it's hash. |
Recursively omit keys from an object by defining an array of keys to exclude in ES6 + Typescript.
|
FWIW: here's my version |
|
@mxmzb the main use-case that isn't supported is arrays (iterate over all items in an array) |
@Billy- If you have explicit values and care about data structure, which I believe you should do, this is a very elegant approach: const myNewObjectWithOmittedParams = Object.assign(
{},
{
...omit(myOldObject, ["bar", "foo.bar"])
},
{
someChildArrayProp: myOldObject.someChildArrayProp.map(obj => omit(obj, ["bar", "foo.bar"]))
}
} |
@mxmzb Edit: It doensn't work with the lastest
|
@clodal That works (I also had the same use case with |
Can you post your version? |
@PizzaBrandon - Awesomesauce solution! |
@clodal thank you
|
@jeshio This is an NPE } else if (typeof value === 'object' && arrItem !== null) {
|
Per all the responses here, it looks like there's a demand IMO. |
you can use function omitDeep(input, excludes) {
const omit = [];
const clone = _.cloneDeepWith(input, (value, key, object, stack) => {
if(!_.isUndefined(key) && excludes.includes(key)) {
omit.push({ key, from: stack.get(object) });
return null;
}
});
omit.forEach(({ key, from }) => _.unset(from, key));
return clone;
} I've been using something a bit more involved to omit anything past a given depth or have exclusion rules be regexes on full paths from the root of the input: function deepCustomizer(customizer) {
const depthMap = new WeakMap();
return (value, key, object, stack) => {
let depth = 0;
let path = [];
if (!_.isUndefined(key)) {
const { depth: parentDepth, path: parentPath } = depthMap.get(object);
depth = parentDepth + 1;
path = [...parentPath, key];
}
if (_.isObject(value) && !_.isBuffer(value)) {
depthMap.set(value, { depth, path });
}
return customizer(value, key, object, stack, depth, path);
};
}
function omitDeep(input, excludes, maxDepth = Infinity) {
const omit = [];
const isExcluded = pathString => _.some(excludes, exclude => _.isRegExp(exclude) ? exclude.test(pathString) : exclude === pathString);
const clone = _.cloneDeepWith(input, deepCustomizer((value, key, object, stack, depth, path) => {
const pathString = _.join(path, '.');
if(depth > maxDepth || isExcluded(pathString)) {
omit.push({ key, from: stack.get(object) });
return null;
}
}));
omit.forEach(({ key, from }) => _.unset(from, key));
return clone;
} but it would be nice if at least lodash's customizer provides depth/path and a way to instruct omissions, maybe with a Symbol. |
This one breaks when having null values, you can filter them like this:
|
For my use case I just needed to remove undefined variables.. here my attempt.
|
I just had to deep omit certain keys given an object that might contain Arrays. Here's my attempt // eslint-disable-next-line @typescript-eslint/no-explicit-any
export const omitDeep = (obj: any, omitKeys: string[]): any => {
if (Array.isArray(obj)) {
return obj.map((v) => omitDeep(v, omitKeys));
} else if (obj != null && obj.constructor === Object) {
for (const key in obj) {
const value = obj[key];
if (value != null && value.constructor === Object) {
omitDeep(value, omitKeys);
} else if (omitKeys.includes(key)) {
delete obj[key];
}
}
}
return obj;
}; |
Typescript version of #723 (comment): export function omitDeep<T>(collection: T, excludeKeys: string[]): T {
function omitFn(value: any) {
if (value && typeof value === 'object') {
excludeKeys.forEach((key) => {
delete value[key];
});
}
}
return cloneDeepWith(collection, omitFn);
} |
Here's a TypeScript types-aware version (doesn't work with Map and Set, but those can be added): export type OmitDeep<T, K extends string> =
T extends (infer U)[]
? OmitDeep<U, K>[]
: T extends Record<any, any>
? { [P in keyof T as P extends K ? never : P]: OmitDeep<T[P], K> }
: T;
export function omitDeep<
T extends object,
K extends string,
>(obj: T, key: K): OmitDeep<T, K> {
const clone: any = {};
for (const property in obj) {
const value = obj[property];
//@ts-expect-error The types of those values can overlap
if (property === key) {
continue;
}
if (Array.isArray(value)) {
clone[property] = value.map((item) => omitDeep(item, key));
continue;
}
if (value !== null && typeof value === "object") {
clone[property] = omitDeep(value, key);
continue;
}
clone[property] = value;
}
return clone;
} |
I was wondering if there could be an enhancement to support deep functionality for
_.omit
or if it has been discussed before?The text was updated successfully, but these errors were encountered: