-
-
Save bisubus/2da8af7e801ffd813fab7ac221aa7afc to your computer and use it in GitHub Desktop.
|
Object.keys(obj) | |
.filter((key) => ['blacklisted', 'keys'].indexOf(key) < 0) | |
.reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {}) |
Object.entries(obj) | |
.filter(([key]) => !['blacklisted', 'keys'].includes(key)) | |
.reduce((obj, [key, val]) => Object.assign(obj, { [key]: val }), {}); |
Object.fromEntries( | |
Object.entries(obj) | |
.filter(([key]) => !['blacklisted', 'keys'].includes(key)) | |
); |
Object.keys(obj) | |
.filter((key) => ['whitelisted', 'keys'].indexOf(key) >= 0) | |
.reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {}) |
Object.entries(obj) | |
.filter(([key]) => ['whitelisted', 'keys'].includes(key)) | |
.reduce((obj, [key, val]) => Object.assign(obj, { [key]: val }), {}); |
Object.fromEntries( | |
Object.entries(obj) | |
.filter(([key]) => ['whitelisted', 'keys'].includes(key)) | |
); |
@sylvainpolletvillard Thanks! I'm using babel, so I appreciate both alternatives. But in fact the 2nd one (Rest/Spread Properties) is not part of ES2017, it might be part of ES2018 though: http://2ality.com/2017/02/ecmascript-2018.html
⌣
Another version of pick with object spread:
{...['whitelisted', 'key'].reduce((mem, key) => ({ ...mem, [key]: obj[key] }), {})}
and with typescript (>2.1):
/**
* Creates an object composed of the picked object properties.
* @param obj The source object
* @param paths The property paths to pick
*/
export function pick<T, K extends keyof T>(obj: T, paths: K[]): Pick<T, K> {
return { ...paths.reduce((mem, key) => ({ ...mem, [key]: obj[key] }), {}) } as Pick<T, K>;
}
Please note that we can't use map
here (the @sylvainpolletvillard alternative was not working as expected)
const obj = {a: 1, b: 2, c: 3};
{...['a', 'c'].reduce((mem, key) => ({ ...mem, [key]: obj[key] }), {})} // {a: 1, c: 3}
{...['a', 'c'].map((key) => ({ [key]: obj[key] }))} // {0: {a: 1}, 1: {c: 3}}
Btw thanks for all these nice ideas of implementation 👍
Another one for pick:
(({whitelisted, key}) => ({whitelisted, key}))(obj)
But I find them all a bit lame to be honest ;-)
The only alternative that still preserves most of the readability and simplicity of _.pick
and _.omit
:
... none.
I'm giving up and just using lodash for _.pick
and _.omit
Object.prototype.map = function (fn) {
return fn(this)
}
const a = { x: 1, y: 2, z: 3 }
// Pick x, y
const { x, y } = a.map(({ x, y }) => ({ x, y })
// Omit x, y
const { z } = a.map(({ x, y, ...rest }) => rest))
To me, the easiest solutions are :
const foo = { a:1, b:2, c:3 }
// pick a
const { a } = foo
// omit a
const { a, ...desiredFoo } = foo
Now if you have:
const foo = {a:1, b:2, c:3 }
const bar = {a:1, b:4, c:6 }
You can solve conflict, either like this:
// pick a
const { a } = foo
const { a:z } = bar
// omit a
const { a, ...desiredFoo } = foo
const { a:z, ...desiredBar } = bar
I personally think this is not so readable.
So I do this instead:
// pick a
const fooA = (({ a }) => a)(foo)
const barA = (({ a }) => a)(bar)
// omit a
const desiredFoo = (({ a, ...rest }) => rest)(foo)
const desiredBar = (({ a, ...rest }) => rest)(bar)
Pick your solution :D
Special thanks @nekuz0r for all his insides !
It's not beautiful but this is what I ended up using to strip a bunch of sensitive keys in an app i'm building. I feel like a year from now I'll still nkow what the syntax means and some of these I have had to go back and figure out later.
// *dirty* is a large database record object
// *whitelist* is an array of acceptable keys
var holder = Object.create(null);
for (key of whitelist) {
holder[key] = dirty[key];
}
Another version of pick with object spread:
{...['whitelisted', 'key'].reduce((mem, key) => ({ ...mem, [key]: obj[key] }), {})}and with typescript (>2.1):
/** * Creates an object composed of the picked object properties. * @param obj The source object * @param paths The property paths to pick */ export function pick<T, K extends keyof T>(obj: T, paths: K[]): Pick<T, K> { return { ...paths.reduce((mem, key) => ({ ...mem, [key]: obj[key] }), {}) } as Pick<T, K>; }Please note that we can't use
map
here (the @sylvainpolletvillard alternative was not working as expected)const obj = {a: 1, b: 2, c: 3}; {...['a', 'c'].reduce((mem, key) => ({ ...mem, [key]: obj[key] }), {})} // {a: 1, c: 3} {...['a', 'c'].map((key) => ({ [key]: obj[key] }))} // {0: {a: 1}, 1: {c: 3}}Btw thanks for all these nice ideas of implementation
No need for wrap and spread { ...a.reduce((acc, next) => acc, {}) }
More efficient omit:
const omit = (o, ...keys) => keys.reduce((memo, key) => {
const { [key]: ignored, ...rest } = memo
return rest
}, o)
Another omit:
function omit(obj,keys){return keys.reduce((r,key)=>(delete r[key],r),{...obj})}
Benchmark:
http://jsben.ch/TISS9
ES5 omit:
function omit(obj, keys) {
const n = {};
Object.keys(obj).forEach(function(key) {
if (keys.indexOf(key) === -1) {
n[key] = obj[key];
}
});
return n;
}
Not omit nor pick but I found a way to replace _get
:
// falls back to a default value when response.settings is missing or nullish
// (response.settings == null) or when response.settings.animationDuration is missing
// or nullish (response.settings.animationDuration == null)
const animationDuration = _get(response, "settings.animationDuration", 300);
const animationDuration = response.settings?.animationDuration ?? 300;
const buildAnObjectFromAQuery = query => ({
...query.foo && { foo: query.foo },
...query.bar && { bar: query.bar },
});
@kgstew It's good only for cases where only truthy values are useful, e.g. foo and bar are objects. Even better with destructuring:
const buildAnObjectFromAQuery = ({ foo, bar }) => ({
...foo && { foo },
...bar && { bar }
});
Another solution to omit
on a line can be:
const omit = (props, obj) => props.reduce((acc, key) => ((key, {[key]: _, ...rest}) => rest)(key, acc), obj)
Object.assign({}, ...['whitelisted', 'keys'].map(key => ({ [key]: obj[key] })))
This will not work if obj
is an empty object.
Typesafe omit:
export function omit<T extends object, K extends keyof T>(obj: T, paths: K[]): Omit<T, K> {
return {
...paths.reduce((mem, key) => ((k: K, { [k]: ignored, ...rest }) => rest)(key, mem), obj as object),
} as Omit<T, K>;
}
Another solution to pick
const pick = <T extends object, K extends keyof T>(
whitelisted: K[],
target: T,
defaultValue?: any
) =>
Object.fromEntries(
whitelisted.map((key) =>
[ key, key in target ? target[key] : defaultValue ]
)
);
ES2017 alternatives :
pick:
omit with https://github.com/tc39/proposal-object-rest-spread: