Skip to content

fix(pick): return Partial<Pick<T, K>> for non-tuple key arrays#1634

Open
Seojooyeon-creat wants to merge 4 commits intotoss:mainfrom
Seojooyeon-creat:fix/pick-partial-return-type
Open

fix(pick): return Partial<Pick<T, K>> for non-tuple key arrays#1634
Seojooyeon-creat wants to merge 4 commits intotoss:mainfrom
Seojooyeon-creat:fix/pick-partial-return-type

Conversation

@Seojooyeon-creat
Copy link
Copy Markdown

Closes #1623

Summary

  • pick currently returns Pick<T, K> regardless of whether keys is a tuple or a variable-length array. This is incorrect when K is a union type: Pick<T, 'a' | 'b'> implies both a and b are always present, but the runtime value may only contain one of them.
  • This PR fixes the return type using a conditional type that distinguishes between tuple and variable-length array inputs.

Changes

src/object/pick.ts

Changed the signature from:

pick<T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K>

to:

pick<T extends Record<string, any>, Keys extends ReadonlyArray<keyof T>>(
  obj: T,
  keys: readonly [...Keys]
): number extends Keys['length'] ? Partial<Pick<T, Keys[number]>> : Pick<T, Keys[number]>
  • readonly [...Keys] forces TypeScript to infer tuple types for array literals like ['a', 'b']
  • number extends Keys['length'] distinguishes tuple (length is a specific literal) from variable-length array (length is number)
  • Result: literal tuple → Pick<T, K>, variable-length array → Partial<Pick<T, K>>

src/object/pick.spec.ts

Added two type-level tests using expectTypeOf:

  • Literal tuple ['a', 'b']Pick<T, 'a' | 'b'> (all keys guaranteed)
  • Variable array ('a' | 'b')[]Partial<Pick<T, 'a' | 'b'>> (only present keys)

docs/ (en, ko, ja, zh_hans)

Updated parameter and return type descriptions to reflect the new behavior.

Context

A similar fix was previously applied to omit (#1498) using overloads and then reverted (#1595). This PR takes a different approach — a single signature with a conditional return type — which avoids the added complexity of overloads while correctly narrowing the type based on tuple vs. array input.

Benchmark

Runtime logic is unchanged. Performance is maintained:

es-toolkit/pick    19,473,619 hz  (4.40x faster than lodash)

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
es-toolkit Ready Ready Preview, Comment Apr 18, 2026 4:34am

Request Review

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pick: pick should return Partial<Pick<T,K>>

1 participant