-
Notifications
You must be signed in to change notification settings - Fork 510
feat(uniqBy): extend uniqBy to accept property keys #1534
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
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR extends the uniqBy utility function to accept either a selector function or a property key (like 'id' or 'category'), improving ergonomics and consistency with similar functions like sortBy and orderBy. The change maintains full backward compatibility while making common use cases more concise.
Key Changes:
- Extended
uniqBysignature to accept((item: T) => U) | keyof Tinstead of just a function - Updated implementation to handle both selector functions and property key lookups
- Added comprehensive test coverage for property key usage scenarios
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/array/uniqBy.ts | Extended function signature and implementation to support property keys alongside selector functions |
| src/array/uniqBy.spec.ts | Added tests for property key selector usage with numeric and string fields, plus edge cases |
| docs/reference/array/uniqBy.md | Updated English documentation with new API signature and property key examples |
| docs/zh_hans/reference/array/uniqBy.md | Updated Chinese documentation to reflect the new selector parameter and usage patterns |
| docs/ko/reference/array/uniqBy.md | Updated Korean documentation with examples of both selector functions and property keys |
| docs/ja/reference/array/uniqBy.md | Updated Japanese documentation to describe both selector function and property key usage |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| */ | ||
| export function uniqBy<T, U>(arr: readonly T[], mapper: (item: T) => U): T[] { | ||
| const map = new Map<U, T>(); | ||
| export function uniqBy<T, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[] { |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The generic type T should be constrained with extends object for type safety when accepting property keys. Similar functions in the codebase (sortBy and orderBy) use this constraint. Without it, callers could pass primitive types with property keys, leading to runtime errors. Change to: export function uniqBy<T extends object, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[]
| export function uniqBy<T, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[] { | |
| export function uniqBy<T extends object, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, constraining T with extends object here would introduce a breaking change. uniqBy currently supports primitive arrays (e.g. uniqBy([1.2, 1.5, 2.3], Math.floor)), and this pattern is already documented and tested. If we change the signature to T extends object, those existing usages would no longer type-check.
Because of that, I’d prefer not to add the extends object constraint on T for uniqBy in this PR. I’d like to keep primitive use cases supported and avoid turning this into a breaking change.
| export function uniqBy<T, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[] { | ||
| const map = new Map<U | T[keyof T], T>(); |
Copilot
AI
Nov 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Map key type U | T[keyof T] is overly broad and doesn't accurately represent the actual key types. When selector is a property key K, the key should be T[K], not T[keyof T]. Consider using function overloads to provide more precise typing:\ntypescript\nexport function uniqBy<T extends object, K extends keyof T>(arr: readonly T[], selector: K): T[];\nexport function uniqBy<T extends object, U>(arr: readonly T[], selector: (item: T) => U): T[];\nexport function uniqBy<T extends object, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[] {\n // implementation\n}\n
| export function uniqBy<T, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[] { | |
| const map = new Map<U | T[keyof T], T>(); | |
| export function uniqBy<T extends object, K extends keyof T>(arr: readonly T[], selector: K): T[]; | |
| export function uniqBy<T, U>(arr: readonly T[], selector: (item: T) => U): T[]; | |
| export function uniqBy<T, U>(arr: readonly T[], selector: ((item: T) => U) | keyof T): T[] { | |
| const map = new Map<any, T>(); |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1534 +/- ##
=======================================
Coverage 99.97% 99.97%
=======================================
Files 474 474
Lines 4492 4492
Branches 1313 1314 +1
=======================================
Hits 4491 4491
Misses 1 1 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
bertyhell
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Closed #1512
Description
This PR updates the
uniqByutility to support both selector functions and property keys, and aligns its documentation and tests with the new API.The goal is to make
uniqByeasier to use in common cases (e.g. deduplicating by'id'or'category') while keeping full backward compatibility with the existing function-based usage.Changes
uniqByfunction signature to accept aselectorparameter of type((item: T) => U) | keyof Tinstead of a mapper function only.uniqBynow usesMap<U | T[keyof T], T>as the backing store so it can handle keys produced either by a selector function (U) or by a property lookup (T[keyof T]).selector(item)whenselectoris a function, oritem[selector]whenselectoris a property key.uniqByusage with property keys (e.g.uniqBy(items, 'id'),uniqBy(products, 'category')), in addition to the existing selector-function tests.uniqByMDX docs:mapperwithselectorin the API description and examples.'age','category').Motivation
uniqByalready encourages a “pick a value and deduplicate by it” pattern, but requiring an arrow function for simple cases (e.g.uniqBy(users, u => u.id)) can be unnecessarily verbose. SincesortByin the same toolkit already supports both property keys and selector functions, extendinguniqByin a similar way improves API consistency and ergonomics.This change makes common usage like
uniqBy(users, 'id')oruniqBy(products, 'category')more readable, without forcing any changes on existing call sites.Breaking Changes
There are no breaking changes in this PR.
uniqBy(array, x => x.someField)remain valid and type-compatible.mappertoselector, but the function still accepts any previous function-based selector.