Skip to content

Instantly share code, notes, and snippets.

@bisubus
Last active April 13, 2024 21:03
Show Gist options
  • Save bisubus/2da8af7e801ffd813fab7ac221aa7afc to your computer and use it in GitHub Desktop.
Save bisubus/2da8af7e801ffd813fab7ac221aa7afc to your computer and use it in GitHub Desktop.
ES5/ES6/ES2017/ES2019 omit & pick
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
Copy link

ES2017 alternatives :

pick:

Object.assign({}, ...['whitelisted', 'keys'].map(key => ({ [key]: obj[key] })))

omit with https://github.com/tc39/proposal-object-rest-spread:

const { blacklisted, keys, ...result } = obj;

@protron
Copy link

protron commented May 27, 2017

@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

@JeffML
Copy link

JeffML commented Jul 31, 2017

@fabien0102
Copy link

fabien0102 commented Mar 1, 2018

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 👍

@betabong
Copy link

betabong commented Aug 22, 2018

Another one for pick:

(({whitelisted, key}) => ({whitelisted, key}))(obj)

But I find them all a bit lame to be honest ;-)

@jeremymoritz
Copy link

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

@justinmchase
Copy link

justinmchase commented Jan 8, 2019

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))

@OlivierCuyp
Copy link

OlivierCuyp commented Mar 26, 2019

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 !

@charrismatic
Copy link

charrismatic commented Apr 22, 2019

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];
}

@vsnikkil
Copy link

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, {}) }

@Whoaa512
Copy link

Whoaa512 commented Jul 1, 2019

More efficient omit:

const omit = (o, ...keys) => keys.reduce((memo, key) => {
    const { [key]: ignored, ...rest } = memo
	return rest
}, o)

@Nickman87
Copy link

Another omit:
function omit(obj,keys){return keys.reduce((r,key)=>(delete r[key],r),{...obj})}

Benchmark:
http://jsben.ch/TISS9

@boutell
Copy link

boutell commented Feb 9, 2020

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;
}

@taily-khucnaykhongquantrong

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;

@kgstew
Copy link

kgstew commented Jun 12, 2020

const buildAnObjectFromAQuery = query => ({
  ...query.foo && { foo: query.foo },
  ...query.bar && { bar: query.bar },
});

https://medium.com/@mikeh91/conditionally-adding-keys-to-javascript-objects-using-spread-operators-and-short-circuit-evaluation-acf157488ede

@bisubus
Copy link
Author

bisubus commented Jun 14, 2020

@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 }
});

@rpmolina
Copy link

Another solution to omit on a line can be:

const omit = (props, obj) => props.reduce((acc, key) => ((key, {[key]: _, ...rest}) => rest)(key, acc), obj)

@abelsoares
Copy link

Object.assign({}, ...['whitelisted', 'keys'].map(key => ({ [key]: obj[key] })))

This will not work if obj is an empty object.

@jiverson
Copy link

jiverson commented Oct 29, 2021

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>;
}

@ajitsinghkamal
Copy link

ajitsinghkamal commented Jan 20, 2022

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 ]
        )
    );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment