* fix(collection): preserve ReadonlyCollection through tap/each
`each` and `tap` return polymorphic `this`, which TypeScript resolves
against the `Omit<Collection, ...>` portion of `ReadonlyCollection`
rather than the full intersection. That let callers reach `set` and
`delete` on the result of a chain started from a `ReadonlyCollection`:
const ro: ReadonlyCollection<string, number> = new Collection(...);
ro.tap(() => {}).set('x', 0); // compiled, mutated the underlying Map
The fix omits `each` and `tap` from the base `Omit` and re-declares
them on the `ReadonlyCollection` side of the intersection so the return
type narrows back to `ReadonlyCollection`.
Closes#10514
* test(collection): gate readonly-chain checks behind if(false)
Previously the `@ts-expect-error` lines still executed the `set` and
`delete` mutations at runtime, and the final `size === 1` passed only
because they happened to cancel out. Wrapping the assertions in
`if (false)` keeps the compile-time guarantee while the backing
collection is truly untouched, and adds a `get('a') === 1` check as
a belt.
* test(collection): move readonly type checks to *.test-d.ts
Addresses review feedback. The type-level assertions around tap() and
each() preserving ReadonlyCollection belong in a *.test-d.ts file so
they run through vitest's typecheck pass instead of runtime.
Replaces the if(false)-gated @ts-expect-error block in collection.test.ts
with expectTypeOf assertions in a new collection.test-d.ts. Covers both
the no-thisArg and with-thisArg overloads of tap and each.
BREAKING CHANGE: This replaces the previously inaccurate default sort algorithm, which may alter sort results where a user-defined comparison function is not provided.
* perf: `merge()`: deduplicate boolean checks
* perf: `toSorted()`: remove redundant closure
* perf: `last[Key]()`: order of operations
- do not perform iterable-to-array until required
- test ! before <
* perf: `{at,keyAt}()`: manually iterate to target
* perf: `first[Key]()`: avoid `Array.from()`
* perf: `map()`: avoid `Array.from()`
* perf: `random[Key]()`: avoid `Array.from()`
* test: `.{at,keyAt}()` indices
* perf: `last[Key]()`: use `.at()`/`.keyAt()` for single element
* perf: `first[Key]()`: use iterable-to-array if returning all
* perf: `random[Key]()`: use `{at,keyAt}()` for single value
- skip iterable-to-array for returning single value
- short-circuit if amount or collection size is zero
* perf: `random[Key]()`: use Durstenfeld shuffle
* refactor: `{key,keyAt}()`: reorder index check
---------
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
feat(collection): align/add methods with/from Set Methods proposal
BREAKING CHANGE: The `intersect` method has been renamed to `intersection`
BREAKING CHANGE: The `difference` method has been renamed to `symmetricDifference`
BREAKING CHANGE: The `subtract` method has been renamed to `difference`