Coding problem · Easy · Language Idioms

Typed pick() and omit()

Easy Language practicals Seen at Microsoft, Atlassian

Implement two helpers that are common in API layers (e.g. stripping password from a user before returning it):

function pick<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K>
function omit<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K>

Neither may mutate obj. pick only includes keys that exist on the object.

Hints

Hint 1

K extends keyof T means only real keys of T can be passed — typos become compile errors.

Hint 2

Copy with { ...obj } and delete for omit, or build a new object from entries.

Write and run your solution

Loading the editor… (JavaScript is required to run code in your browser.)

Solution and explanation

Show the solution

Time O(keys) for pick, O(fields) for omit · Space O(fields)

keyof T constrains the key list at compile time, and the built-in mapped types Pick<T, K> / Omit<T, K> describe the result, so omit(user, ["password"]).password is a type error. At runtime, pick copies own properties only and omit deletes from a shallow copy.

Note that omit is a shallow copy — nested objects are still shared with the original.

Reference solution

function pick<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K> {
  const out = {} as Pick<T, K>;
  for (const key of keys) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) out[key] = obj[key];
  }
  return out;
}

function omit<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K> {
  const copy = { ...obj };
  for (const key of keys) delete copy[key];
  return copy as Omit<T, K>;
}

Common mistakes

  • Mutating the input with delete obj[key].
  • Typing keys as string[], which loses the connection to T.

Follow-up questions

  • Write a DeepReadonly<T> type.
  • Use satisfies to validate config objects without widening.