ts-data-forge 14.0.1 → 14.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +5 -5
  2. package/dist/array/impl/array-utils-transformation.d.mts +4 -1
  3. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  4. package/dist/array/impl/array-utils-transformation.mjs +4 -5
  5. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  6. package/dist/array/impl/array-utils-validation.d.mts +8 -3
  7. package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
  8. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  9. package/dist/collections/imap-mapped.mjs +1 -1
  10. package/dist/collections/imap-mapped.mjs.map +1 -1
  11. package/dist/collections/imap.mjs +1 -1
  12. package/dist/collections/imap.mjs.map +1 -1
  13. package/dist/functional/match.d.mts.map +1 -1
  14. package/dist/functional/match.mjs.map +1 -1
  15. package/dist/number/branded-types/int.d.mts +1 -1
  16. package/dist/number/branded-types/int16.d.mts +1 -1
  17. package/dist/number/branded-types/int32.d.mts +1 -1
  18. package/dist/number/branded-types/non-negative-int16.d.mts +1 -1
  19. package/dist/number/branded-types/non-negative-int32.d.mts +1 -1
  20. package/dist/number/branded-types/non-positive-finite-number.mjs +1 -1
  21. package/dist/number/branded-types/non-positive-finite-number.mjs.map +1 -1
  22. package/dist/number/branded-types/positive-int.d.mts +1 -1
  23. package/dist/number/branded-types/positive-int16.d.mts +1 -1
  24. package/dist/number/branded-types/positive-int32.d.mts +1 -1
  25. package/dist/number/branded-types/positive-safe-int.d.mts +1 -1
  26. package/dist/number/branded-types/positive-uint16.d.mts +1 -1
  27. package/dist/number/branded-types/positive-uint32.d.mts +1 -1
  28. package/dist/number/branded-types/safe-int.d.mts +1 -1
  29. package/dist/number/branded-types/safe-uint.d.mts +1 -1
  30. package/dist/number/branded-types/uint.d.mts +1 -1
  31. package/dist/number/branded-types/uint16.d.mts +1 -1
  32. package/dist/number/branded-types/uint32.d.mts +1 -1
  33. package/dist/number/enum/int8.d.mts +2 -2
  34. package/dist/number/enum/int8.d.mts.map +1 -1
  35. package/dist/number/enum/int8.mjs.map +1 -1
  36. package/dist/number/enum/uint8.d.mts +2 -2
  37. package/dist/number/enum/uint8.d.mts.map +1 -1
  38. package/dist/number/enum/uint8.mjs.map +1 -1
  39. package/dist/number/num-arithmetic-types.d.mts +8 -9
  40. package/dist/number/num-arithmetic-types.d.mts.map +1 -1
  41. package/dist/number/refined-number-utils.d.mts +2 -2
  42. package/dist/number/refined-number-utils.d.mts.map +1 -1
  43. package/dist/number/refined-number-utils.mjs.map +1 -1
  44. package/dist/object/object.d.mts +12 -12
  45. package/dist/object/object.d.mts.map +1 -1
  46. package/dist/object/object.mjs +5 -1
  47. package/dist/object/object.mjs.map +1 -1
  48. package/dist/others/fast-deep-equal.d.mts.map +1 -1
  49. package/dist/others/fast-deep-equal.mjs +2 -2
  50. package/dist/others/fast-deep-equal.mjs.map +1 -1
  51. package/package.json +2 -2
  52. package/src/array/impl/array-utils-modification.test.mts +26 -5
  53. package/src/array/impl/array-utils-shape-invariants.test.mts +259 -17
  54. package/src/array/impl/array-utils-slicing.test.mts +11 -3
  55. package/src/array/impl/array-utils-transformation.mts +41 -18
  56. package/src/array/impl/array-utils-transformation.test.mts +10 -3
  57. package/src/array/impl/array-utils-validation.mts +54 -10
  58. package/src/array/impl/array-utils-validation.test.mts +153 -3
  59. package/src/collections/imap-mapped.mts +1 -1
  60. package/src/collections/imap-mapped.test.mts +2 -2
  61. package/src/collections/imap.mts +1 -1
  62. package/src/collections/iset-mapped.test.mts +1 -1
  63. package/src/functional/match.mts +5 -4
  64. package/src/functional/result.test.mts +5 -2
  65. package/src/guard/is-primitive.test.mts +1 -1
  66. package/src/guard/is-record.test.mts +4 -4
  67. package/src/guard/is-type.test.mts +2 -2
  68. package/src/number/branded-types/finite-number.test.mts +2 -2
  69. package/src/number/branded-types/non-negative-finite-number.test.mts +2 -2
  70. package/src/number/branded-types/non-positive-finite-number.mts +1 -1
  71. package/src/number/branded-types/non-positive-finite-number.test.mts +5 -9
  72. package/src/number/branded-types/non-zero-finite-number.test.mts +2 -2
  73. package/src/number/branded-types/positive-finite-number.test.mts +2 -2
  74. package/src/number/enum/int8.mts +2 -1
  75. package/src/number/enum/uint8.mts +6 -2
  76. package/src/number/num-arithmetic-types.mts +125 -24
  77. package/src/number/num.test.mts +9 -9
  78. package/src/number/refined-number-utils.mts +2 -1
  79. package/src/object/object.mts +29 -17
  80. package/src/object/object.test.mts +2 -1
  81. package/src/others/fast-deep-equal.mts +6 -4
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.mts","sourceRoot":"","sources":["../../src/object/object.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"object.d.mts","sourceRoot":"","sources":["../../src/object/object.mts"],"names":[],"mappings":"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"}
@@ -85,7 +85,11 @@ var Obj;
85
85
  case 1: {
86
86
  const [keys] = args;
87
87
  return (record) => {
88
- const result = omit(record, keys);
88
+ const result = omit(
89
+ record,
90
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
91
+ keys
92
+ );
89
93
  return result;
90
94
  };
91
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"object.mjs","sources":["../../src/object/object.mts"],"sourcesContent":["import {\n type ArrayElement,\n type Decrement,\n type DeepOmit,\n type DeepPick,\n type IsFixedLengthList,\n type IsUnion,\n type List,\n type ReadonlyRecord,\n type RelaxedPick,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport { Arr } from '../array/index.mjs';\nimport { hasKey, isRecord } from '../guard/index.mjs';\n\n/**\n * A collection of type-safe object utility functions providing functional\n * programming patterns for object manipulation, including pick, omit, shallow\n * equality checks, and more.\n *\n * All functions maintain TypeScript type safety and support both direct and\n * curried usage patterns for better composition with pipe operations.\n */\nexport namespace Obj {\n /**\n * Performs a shallow equality check on two records using a configurable\n * equality function. Verifies that both records have the same number of\n * entries and that for every key in the first record, the corresponding value\n * passes the equality test with the value in the second record.\n *\n * @example\n *\n * ```ts\n * const obj1 = { name: 'Alice', age: 30 } as const;\n *\n * const obj2 = { name: 'Alice', age: 30 } as const;\n *\n * const obj3 = { name: 'Alice', age: 31 } as const;\n *\n * assert.isTrue(Obj.shallowEq(obj1, obj2));\n *\n * assert.isFalse(Obj.shallowEq(obj1, obj3));\n *\n * // Custom equality function\n * const obj4 = { value: 1 } as const;\n *\n * const obj5 = { value: 1.00001 } as const;\n *\n * const closeEnough = (a: unknown, b: unknown): boolean => {\n * if (typeof a === 'number' && typeof b === 'number') {\n * return Math.abs(a - b) < 0.001;\n * }\n *\n * return Object.is(a, b);\n * };\n *\n * assert.isTrue(Obj.shallowEq(obj4, obj5, closeEnough));\n * ```\n *\n * @param a - The first record to compare\n * @param b - The second record to compare\n * @param eq - Optional equality function (defaults to Object.is for strict\n * equality)\n * @returns `true` if the records are shallowly equal according to the\n * equality function, `false` otherwise\n */\n export const shallowEq = (\n a: UnknownRecord,\n b: UnknownRecord,\n eq: (x: unknown, y: unknown) => boolean = Object.is,\n ): boolean => {\n const aEntries = Object.entries(a);\n\n const bEntries = Object.entries(b);\n\n if (aEntries.length !== bEntries.length) return false;\n\n return aEntries.every(([k, v]) => eq(b[k], v));\n };\n\n /**\n * Creates a new record that contains only the specified keys from the source\n * record. This function supports both direct usage and curried form for\n * functional composition.\n *\n * **Type Safety**: Only keys that exist in the source record type are\n * allowed, preventing runtime errors from accessing non-existent properties.\n *\n * @example\n *\n * ```ts\n * const user = {\n * id: 1,\n * name: 'Bob',\n * email: 'bob@example.com',\n * password: 'secret',\n * role: 'admin',\n * } as const;\n *\n * // Direct usage\n * const publicInfo = Obj.pick(user, ['id', 'name', 'role']);\n *\n * assert.deepStrictEqual(publicInfo, {\n * id: 1,\n * name: 'Bob',\n * role: 'admin',\n * });\n *\n * // Curried usage with pipe\n * const nameAndEmail = pipe(user).map(Obj.pick(['name', 'email'])).value;\n *\n * assert.deepStrictEqual(nameAndEmail, {\n * name: 'Bob',\n * email: 'bob@example.com',\n * });\n * ```\n *\n * @template R - The type of the input record\n * @template Keys - The readonly array type of keys to pick from the record\n * @param record - The source record to pick properties from\n * @param keys - A readonly array of keys to include in the result\n * @returns A new record containing only the specified keys and their values\n */\n export function pick<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(record: R, keys: Keys): Pick<R, ArrayElement<Keys>>;\n\n // Curried version\n export function pick<const Keys extends readonly PropertyKey[]>(\n keys: Keys,\n ): <const R extends UnknownRecord>(\n record: R,\n ) => RelaxedPick<R, ArrayElement<Keys>>;\n\n export function pick<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(\n ...args: readonly [record: R, keys: Keys] | readonly [keys: Keys]\n ):\n | Pick<R, ArrayElement<Keys>>\n | ((record: R) => RelaxedPick<R, ArrayElement<Keys>>) {\n switch (args.length) {\n case 2: {\n const [record, keys] = args;\n\n const keysSet = new Set<keyof R>(keys);\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(\n Object.entries(record).filter(([k, _v]) => keysSet.has(k)),\n ) as never\n );\n }\n\n case 1: {\n const [keys] = args;\n\n return (record: R) => pick(record, keys);\n }\n }\n }\n\n /**\n * Creates a new record that excludes the specified keys from the source\n * record. This function supports both direct usage and curried form for\n * functional composition.\n *\n * **Type Safety**: Only keys that exist in the source record type are\n * allowed, and the return type precisely reflects which properties remain\n * after omission.\n *\n * @example\n *\n * ```ts\n * const user = {\n * id: 1,\n * name: 'Charlie',\n * email: 'charlie@example.com',\n * password: 'secret123',\n * internalNote: 'VIP customer',\n * } as const;\n *\n * // Direct usage - remove sensitive fields\n * const safeUser = Obj.omit(user, ['password', 'internalNote']);\n *\n * assert.deepStrictEqual(safeUser, {\n * id: 1,\n * name: 'Charlie',\n * email: 'charlie@example.com',\n * });\n *\n * // Curried usage with pipe\n * const withoutEmail = pipe(user).map(Obj.omit(['email', 'password'])).value;\n *\n * assert.deepStrictEqual(withoutEmail, {\n * id: 1,\n * name: 'Charlie',\n * internalNote: 'VIP customer',\n * });\n * ```\n *\n * @template R - The type of the input record\n * @template Keys - The readonly array type of keys to omit from the record\n * @param record - The source record to omit properties from\n * @param keys - A readonly array of keys to exclude from the result\n * @returns A new record containing all properties except the specified keys\n */\n export function omit<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(record: R, keys: Keys): Omit<R, ArrayElement<Keys>>;\n\n // Curried version\n export function omit<const Keys extends readonly PropertyKey[]>(\n keys: Keys,\n ): <const R extends UnknownRecord>(record: R) => Omit<R, ArrayElement<Keys>>;\n\n export function omit<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(\n ...args:\n readonly [record: R, keys: Keys] | readonly [keys: readonly PropertyKey[]]\n ):\n Omit<R, ArrayElement<Keys>> | ((record: R) => Omit<R, ArrayElement<Keys>>) {\n switch (args.length) {\n case 2: {\n const [record, keys] = args;\n\n const keysSet = new Set<keyof R>(keys);\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(\n Object.entries(record).filter(([k, _v]) => !keysSet.has(k)),\n ) as never\n );\n }\n\n case 1: {\n const [keys] = args;\n\n return <R2 extends UnknownRecord>(record: R2) => {\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n const result = omit(record, keys as readonly (keyof R2)[]) as Omit<\n R2,\n ArrayElement<Keys>\n >;\n\n return result;\n };\n }\n }\n }\n\n /**\n * Creates an object from an array of key-value pairs with precise TypeScript\n * typing. This is a type-safe wrapper around `Object.fromEntries` that\n * provides better type inference and compile-time guarantees about the\n * resulting object structure.\n *\n * **Type Behavior**:\n *\n * - When entries is a fixed-length tuple, the exact object type is inferred\n * - When entries has dynamic length with union key types, `Partial` is applied\n * to prevent incorrect assumptions about which keys will be present\n *\n * @example\n *\n * ```ts\n * // Fixed-length tuple - exact type inferred\n * const entries1 = [\n * ['name', 'David'],\n * ['age', 25],\n * ['active', true],\n * ] as const;\n *\n * const obj1 = Obj.fromEntries(entries1);\n *\n * assert.deepStrictEqual(obj1, {\n * name: 'David',\n * age: 25,\n * active: true,\n * });\n *\n * // Dynamic length array - Partial type applied\n * const dynamicEntries: readonly (readonly ['x' | 'y', number])[] = [\n * ['x', 10],\n * ['y', 20],\n * ] as const;\n *\n * const obj2 = Obj.fromEntries(dynamicEntries);\n *\n * assert.deepStrictEqual(obj2, { x: 10, y: 20 });\n * ```\n *\n * @template Entries - The readonly array type of key-value entry tuples\n * @param entries - An array of readonly key-value entry tuples `[key, value]`\n * @returns An object created from the entries with precise typing\n */\n export const fromEntries = <\n const Entries extends readonly (readonly [PropertyKey, unknown])[],\n >(\n entries: Entries,\n ): IsFixedLengthList<Entries> extends true\n ? TsDataForgeInternals.EntriesToObject<Entries>\n : TsDataForgeInternals.PartialIfKeyIsUnion<\n TsDataForgeInternals.KeysOfEntries<Entries>,\n ReadonlyRecord<\n TsDataForgeInternals.KeysOfEntries<Entries>,\n TsDataForgeInternals.ValuesOfEntries<Entries>\n >\n > =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(entries) as never;\n\n /**\n * Merges multiple records into a single record using `Object.assign`.\n * Later records override properties from earlier records with the same key.\n *\n * @example\n *\n * <!-- doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->\n *\n * ```ts\n * const a = { a: 0, b: 0 } as const;\n *\n * const b = { b: 1, c: 0 } as const;\n *\n * const result = Obj.merge(a, b);\n *\n * assert.deepStrictEqual(result, { a: 0, b: 1, c: 0 });\n * ```\n *\n * <!-- /doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->\n *\n * @param records - The records to merge\n * @returns A new record with all properties merged\n */\n export const merge = <const Records extends readonly UnknownRecord[]>(\n ...records: Records\n ): TsDataForgeInternals.MergeAll<Records> =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(records.flatMap((r) => Object.entries(r))) as never;\n\n /**\n * Deeply picks a nested property from an object along the specified key path.\n * Supports both direct and curried usage.\n *\n * @example\n *\n * ```ts\n * const data = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 } as const;\n *\n * // Direct usage\n * const result = Obj.deepPick(data, ['a', 'b', 'c']);\n *\n * assert.deepStrictEqual(result, { a: { b: { c: 1 } } });\n *\n * // Curried usage with pipe\n * const pickAB = Obj.deepPick(['a', 'b']);\n *\n * const result2 = pipe(data).map(pickAB).value;\n *\n * assert.deepStrictEqual(result2, { a: { b: { c: 1, d: 2 } } });\n * ```\n *\n * @template R - The type of the input record\n * @template Path - The key path tuple\n * @param record - The source record\n * @param path - A readonly tuple of keys representing the nested path\n * @returns A new record containing only the nested property at the path\n */\n export function deepPick<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(record: R, path: Path): DeepPick<R, Path>;\n\n // Curried version\n export function deepPick<const Path extends readonly (string | number)[]>(\n path: Path,\n ): <const R extends UnknownRecord>(record: R) => DeepPick<R, Path>;\n\n export function deepPick<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(\n ...args: readonly [record: R, path: Path] | readonly [path: Path]\n ): DeepPick<R, Path> | ((record: R) => DeepPick<R, Path>) {\n switch (args.length) {\n case 2: {\n const [record, path] = args;\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n deepPickImpl(record, path) as never\n );\n }\n\n case 1: {\n const [path] = args;\n\n return (record: R) => deepPick(record, path);\n }\n }\n }\n\n /**\n * Deeply omits a nested property from an object along the specified key path.\n * Supports both direct and curried usage.\n *\n * @example\n *\n * ```ts\n * const data = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 } as const;\n *\n * // Direct usage\n * const result = Obj.deepOmit(data, ['a', 'b', 'c']);\n *\n * assert.deepStrictEqual(result, { a: { b: { d: 2 }, e: 3 }, f: 4 });\n *\n * // Curried usage with pipe\n * const omitAB = Obj.deepOmit(['a', 'b']);\n *\n * const result2 = pipe(data).map(omitAB).value;\n *\n * assert.deepStrictEqual(result2, { a: { e: 3 }, f: 4 });\n * ```\n *\n * @template R - The type of the input record\n * @template Path - The key path tuple\n * @param record - The source record\n * @param path - A readonly tuple of keys representing the nested path to omit\n * @returns A new record with the nested property at the path removed\n */\n export function deepOmit<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(record: R, path: Path): DeepOmit<R, Path>;\n\n // Curried version\n export function deepOmit<const Path extends readonly (string | number)[]>(\n path: Path,\n ): <const R extends UnknownRecord>(record: R) => DeepOmit<R, Path>;\n\n export function deepOmit<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(\n ...args: readonly [record: R, path: Path] | readonly [path: Path]\n ): DeepOmit<R, Path> | ((record: R) => DeepOmit<R, Path>) {\n switch (args.length) {\n case 2: {\n const [record, path] = args;\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n deepOmitImpl(record, path) as never\n );\n }\n\n case 1: {\n const [path] = args;\n\n return (record: R) => deepOmit(record, path);\n }\n }\n }\n}\n\nconst deepPickImpl = (\n record: UnknownRecord,\n path: readonly (string | number)[],\n): UnknownRecord => {\n if (!Arr.isNonEmpty(path)) return record;\n\n const head = path[0];\n\n if (!hasKey(record, head)) return {};\n\n const value = record[head];\n\n const tail = path.slice(1);\n\n if (!Arr.isNonEmpty(tail)) return { [head]: value };\n\n if (!isRecord(value)) return { [head]: {} };\n\n return {\n [head]: deepPickImpl(value, tail),\n };\n};\n\nconst deepOmitImpl = (\n record: UnknownRecord,\n path: readonly (string | number)[],\n): UnknownRecord => {\n if (!Arr.isNonEmpty(path)) return record;\n\n const head = path[0];\n\n if (!hasKey(record, head)) return record;\n\n const tail = path.slice(1);\n\n if (!Arr.isNonEmpty(tail)) {\n return Object.fromEntries(\n Object.entries(record).filter(([k]) => k !== head),\n );\n }\n\n const value = record[head];\n\n if (!isRecord(value)) return record;\n\n return {\n ...record,\n [head]: deepOmitImpl(value, tail),\n };\n};\n\n/**\n * @internal\n * Internal type utilities for the Obj module.\n */\ndeclare namespace TsDataForgeInternals {\n type RecursionLimit = 20;\n\n /** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */\n export type EntriesToObject<\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n > = Readonly<EntriesToObjectImpl<{}, Entries>>;\n\n /** @internal */\n type EntriesToObjectImpl<\n R,\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n > =\n TypeEq<Entries['length'], 0> extends true\n ? R\n : EntriesToObjectImpl<\n R & Readonly<Record<Entries[0][0], Entries[0][1]>>,\n List.Tail<Entries>\n >;\n\n /**\n * - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`\n * - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |\n * 'b' | 'c' | 'x' | 'y' | 'z'`\n *\n * @note To handle the second example above, recursion needs to be performed on infinite-length Entries,\n * but since the timing to stop cannot be determined, a recursion limit is set.\n */\n export type KeysOfEntries<\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n > = KeysOfEntriesImpl<never, Entries, RecursionLimit>;\n\n type KeysOfEntriesImpl<\n K,\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n RemainingNumRecursions extends number,\n > =\n TypeEq<RemainingNumRecursions, 0> extends true\n ? K\n : TypeEq<Entries['length'], 0> extends true\n ? K\n : KeysOfEntriesImpl<\n K | Entries[0][0],\n List.Tail<Entries>,\n Decrement<RemainingNumRecursions>\n >;\n\n export type ValuesOfEntries<\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n > = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;\n\n type ValuesOfEntriesImpl<\n K,\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n RemainingNumRecursions extends number,\n > =\n TypeEq<RemainingNumRecursions, 0> extends true\n ? K\n : TypeEq<Entries['length'], 0> extends true\n ? K\n : ValuesOfEntriesImpl<\n K | Entries[0][1],\n List.Tail<Entries>,\n Decrement<RemainingNumRecursions>\n >;\n\n export type PartialIfKeyIsUnion<K, T> =\n IsUnion<K> extends true ? Partial<T> : T;\n\n /**\n * Merges two object types where keys in B override keys in A, preserving optional modifiers.\n *\n * This implementation uses a sophisticated technique to preserve optional property modifiers (`?`)\n * during the merge operation, which would otherwise be lost in a naive mapped type implementation.\n *\n * ## Core Technique: Optional Property Detection\n *\n * Uses `{} extends Pick<T, K>` to determine if a property is optional:\n * - **Required property**: `Pick<T, 'x'>` = `{ x: number }` → `{}` does NOT extend it (false)\n * - **Optional property**: `Pick<T, 'y'>` = `{ y?: string }` → `{}` DOES extend it (true)\n *\n * This works because `{}` (empty object) is assignable to objects with only optional properties\n * but not to objects with required properties.\n *\n * ## Implementation Strategy\n *\n * The type is constructed as an intersection of five mapped types:\n *\n * 1. **Required properties from B** - Properties in B that are required (override A completely)\n * 2. **Optional properties from B (not in A)** - New optional properties from B\n * 3. **Optional properties from B (in A)** - Union of A[K] | B[K] to preserve both possibilities\n * 4. **Required properties only in A** - Properties in A but not in B that are required\n * 5. **Optional properties only in A** - Properties in A but not in B that are optional (with `?` modifier)\n *\n * Finally, the intersection is flattened using an optional-preserving identity mapping that\n * re-applies the optional detection logic to maintain the `?` modifiers in the final type.\n *\n * @example\n * ```ts\n * type A = Readonly<{ x: number; y?: string }>;\n *\n * type B = Readonly<{ y?: number; z?: boolean }>;\n *\n * type Result = MergeTwo<A, B>;\n * // Result: Readonly<{ x: number; y?: string | number; z?: boolean }>\n * ```\n */\n // transformer-ignore-next-line\n type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = {\n // 1. Required properties from B (override A completely)\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n readonly [K in keyof B as {} extends Pick<B, K> ? never : K]: B[K];\n } & {\n // 2. Optional properties from B that are NOT in A\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in keyof B as {} extends Pick<B, K>\n ? K extends keyof A\n ? never\n : K\n : never\n ]?: B[K];\n } & {\n // 3. Optional properties from B that ARE in A (create union)\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in keyof B as {} extends Pick<B, K>\n ? K extends keyof A\n ? K\n : never\n : never\n ]?: K extends keyof A ? A[K] | B[K] : never;\n } & {\n // 4. Required properties only in A (not overridden by B)\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? never : K\n ]: A[K];\n } & {\n // 5. Optional properties only in A (not overridden by B)\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? K : never\n ]?: A[K];\n } extends infer O\n ? Readonly<\n {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n [K in keyof O as {} extends Pick<O, K> ? never : K]: O[K];\n } & {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n [K in keyof O as {} extends Pick<O, K> ? K : never]?: O[K];\n }\n >\n : never;\n\n /** Sequentially merges a tuple of object types from left to right. */\n export type MergeAll<\n Records extends readonly UnknownRecord[],\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n Acc extends UnknownRecord = {},\n > =\n IsFixedLengthList<Records> extends false\n ? ArrayElement<Records>\n : Records extends readonly [\n infer First extends UnknownRecord,\n ...infer Rest extends readonly UnknownRecord[],\n ]\n ? MergeAll<Rest, MergeTwo<Acc, First>>\n : Acc;\n}\n"],"names":["Obj","Arr.isNonEmpty"],"mappings":"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"}
1
+ {"version":3,"file":"object.mjs","sources":["../../src/object/object.mts"],"sourcesContent":["import {\n type ArrayElement,\n type Decrement,\n type DeepOmit,\n type DeepPick,\n type IsFixedLengthList,\n type IsUnion,\n type List,\n type ReadonlyRecord,\n type RelaxedExclude,\n type RelaxedOmit,\n type RelaxedPick,\n type StrictOmit,\n type StrictPick,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport { Arr } from '../array/index.mjs';\nimport { hasKey, isRecord } from '../guard/index.mjs';\n\n/**\n * A collection of type-safe object utility functions providing functional\n * programming patterns for object manipulation, including pick, omit, shallow\n * equality checks, and more.\n *\n * All functions maintain TypeScript type safety and support both direct and\n * curried usage patterns for better composition with pipe operations.\n */\nexport namespace Obj {\n /**\n * Performs a shallow equality check on two records using a configurable\n * equality function. Verifies that both records have the same number of\n * entries and that for every key in the first record, the corresponding value\n * passes the equality test with the value in the second record.\n *\n * @example\n *\n * ```ts\n * const obj1 = { name: 'Alice', age: 30 } as const;\n *\n * const obj2 = { name: 'Alice', age: 30 } as const;\n *\n * const obj3 = { name: 'Alice', age: 31 } as const;\n *\n * assert.isTrue(Obj.shallowEq(obj1, obj2));\n *\n * assert.isFalse(Obj.shallowEq(obj1, obj3));\n *\n * // Custom equality function\n * const obj4 = { value: 1 } as const;\n *\n * const obj5 = { value: 1.00001 } as const;\n *\n * const closeEnough = (a: unknown, b: unknown): boolean => {\n * if (typeof a === 'number' && typeof b === 'number') {\n * return Math.abs(a - b) < 0.001;\n * }\n *\n * return Object.is(a, b);\n * };\n *\n * assert.isTrue(Obj.shallowEq(obj4, obj5, closeEnough));\n * ```\n *\n * @param a - The first record to compare\n * @param b - The second record to compare\n * @param eq - Optional equality function (defaults to Object.is for strict\n * equality)\n * @returns `true` if the records are shallowly equal according to the\n * equality function, `false` otherwise\n */\n export const shallowEq = (\n a: UnknownRecord,\n b: UnknownRecord,\n eq: (x: unknown, y: unknown) => boolean = Object.is,\n ): boolean => {\n const aEntries = Object.entries(a);\n\n const bEntries = Object.entries(b);\n\n if (aEntries.length !== bEntries.length) return false;\n\n return aEntries.every(([k, v]) => eq(b[k], v));\n };\n\n /**\n * Creates a new record that contains only the specified keys from the source\n * record. This function supports both direct usage and curried form for\n * functional composition.\n *\n * **Type Safety**: Only keys that exist in the source record type are\n * allowed, preventing runtime errors from accessing non-existent properties.\n *\n * @example\n *\n * ```ts\n * const user = {\n * id: 1,\n * name: 'Bob',\n * email: 'bob@example.com',\n * password: 'secret',\n * role: 'admin',\n * } as const;\n *\n * // Direct usage\n * const publicInfo = Obj.pick(user, ['id', 'name', 'role']);\n *\n * assert.deepStrictEqual(publicInfo, {\n * id: 1,\n * name: 'Bob',\n * role: 'admin',\n * });\n *\n * // Curried usage with pipe\n * const nameAndEmail = pipe(user).map(Obj.pick(['name', 'email'])).value;\n *\n * assert.deepStrictEqual(nameAndEmail, {\n * name: 'Bob',\n * email: 'bob@example.com',\n * });\n * ```\n *\n * @template R - The type of the input record\n * @template Keys - The readonly array type of keys to pick from the record\n * @param record - The source record to pick properties from\n * @param keys - A readonly array of keys to include in the result\n * @returns A new record containing only the specified keys and their values\n */\n export function pick<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(record: R, keys: Keys): StrictPick<R, ArrayElement<Keys>>;\n\n // Curried version\n export function pick<const Keys extends readonly PropertyKey[]>(\n keys: Keys,\n ): <const R extends UnknownRecord>(\n record: R,\n ) => RelaxedPick<R, ArrayElement<Keys>>;\n\n export function pick<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(\n ...args: readonly [record: R, keys: Keys] | readonly [keys: Keys]\n ):\n | StrictPick<R, ArrayElement<Keys>>\n | ((record: R) => RelaxedPick<R, ArrayElement<Keys>>) {\n switch (args.length) {\n case 2: {\n const [record, keys] = args;\n\n const keysSet = new Set<keyof R>(keys);\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(\n Object.entries(record).filter(([k, _v]) => keysSet.has(k)),\n ) as never\n );\n }\n\n case 1: {\n const [keys] = args;\n\n return (record: R) => pick(record, keys);\n }\n }\n }\n\n /**\n * Creates a new record that excludes the specified keys from the source\n * record. This function supports both direct usage and curried form for\n * functional composition.\n *\n * **Type Safety**: Only keys that exist in the source record type are\n * allowed, and the return type precisely reflects which properties remain\n * after omission.\n *\n * @example\n *\n * ```ts\n * const user = {\n * id: 1,\n * name: 'Charlie',\n * email: 'charlie@example.com',\n * password: 'secret123',\n * internalNote: 'VIP customer',\n * } as const;\n *\n * // Direct usage - remove sensitive fields\n * const safeUser = Obj.omit(user, ['password', 'internalNote']);\n *\n * assert.deepStrictEqual(safeUser, {\n * id: 1,\n * name: 'Charlie',\n * email: 'charlie@example.com',\n * });\n *\n * // Curried usage with pipe\n * const withoutEmail = pipe(user).map(Obj.omit(['email', 'password'])).value;\n *\n * assert.deepStrictEqual(withoutEmail, {\n * id: 1,\n * name: 'Charlie',\n * internalNote: 'VIP customer',\n * });\n * ```\n *\n * @template R - The type of the input record\n * @template Keys - The readonly array type of keys to omit from the record\n * @param record - The source record to omit properties from\n * @param keys - A readonly array of keys to exclude from the result\n * @returns A new record containing all properties except the specified keys\n */\n export function omit<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(record: R, keys: Keys): StrictOmit<R, ArrayElement<Keys>>;\n\n // Curried version\n export function omit<const Keys extends readonly PropertyKey[]>(\n keys: Keys,\n ): <const R extends UnknownRecord>(\n record: R,\n ) => RelaxedOmit<R, ArrayElement<Keys>>;\n\n export function omit<\n const R extends UnknownRecord,\n const Keys extends readonly (keyof R)[],\n >(\n ...args:\n readonly [record: R, keys: Keys] | readonly [keys: readonly PropertyKey[]]\n ):\n | StrictOmit<R, ArrayElement<Keys>>\n | ((record: R) => StrictOmit<R, ArrayElement<Keys>>) {\n switch (args.length) {\n case 2: {\n const [record, keys] = args;\n\n const keysSet = new Set<keyof R>(keys);\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(\n Object.entries(record).filter(([k, _v]) => !keysSet.has(k)),\n ) as never\n );\n }\n\n case 1: {\n const [keys] = args;\n\n return <R2 extends UnknownRecord>(record: R2) => {\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n const result = omit(\n record,\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n keys as readonly (keyof R2)[],\n ) as RelaxedOmit<R2, ArrayElement<Keys>>;\n\n return result;\n };\n }\n }\n }\n\n /**\n * Creates an object from an array of key-value pairs with precise TypeScript\n * typing. This is a type-safe wrapper around `Object.fromEntries` that\n * provides better type inference and compile-time guarantees about the\n * resulting object structure.\n *\n * **Type Behavior**:\n *\n * - When entries is a fixed-length tuple, the exact object type is inferred\n * - When entries has dynamic length with union key types, `Partial` is applied\n * to prevent incorrect assumptions about which keys will be present\n *\n * @example\n *\n * ```ts\n * // Fixed-length tuple - exact type inferred\n * const entries1 = [\n * ['name', 'David'],\n * ['age', 25],\n * ['active', true],\n * ] as const;\n *\n * const obj1 = Obj.fromEntries(entries1);\n *\n * assert.deepStrictEqual(obj1, {\n * name: 'David',\n * age: 25,\n * active: true,\n * });\n *\n * // Dynamic length array - Partial type applied\n * const dynamicEntries: readonly (readonly ['x' | 'y', number])[] = [\n * ['x', 10],\n * ['y', 20],\n * ] as const;\n *\n * const obj2 = Obj.fromEntries(dynamicEntries);\n *\n * assert.deepStrictEqual(obj2, { x: 10, y: 20 });\n * ```\n *\n * @template Entries - The readonly array type of key-value entry tuples\n * @param entries - An array of readonly key-value entry tuples `[key, value]`\n * @returns An object created from the entries with precise typing\n */\n export const fromEntries = <\n const Entries extends readonly (readonly [PropertyKey, unknown])[],\n >(\n entries: Entries,\n ): IsFixedLengthList<Entries> extends true\n ? TsDataForgeInternals.EntriesToObject<Entries>\n : TsDataForgeInternals.PartialIfKeyIsUnion<\n TsDataForgeInternals.KeysOfEntries<Entries>,\n ReadonlyRecord<\n TsDataForgeInternals.KeysOfEntries<Entries>,\n TsDataForgeInternals.ValuesOfEntries<Entries>\n >\n > =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(entries) as never;\n\n /**\n * Merges multiple records into a single record using `Object.assign`.\n * Later records override properties from earlier records with the same key.\n *\n * @example\n *\n * <!-- doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->\n *\n * ```ts\n * const a = { a: 0, b: 0 } as const;\n *\n * const b = { b: 1, c: 0 } as const;\n *\n * const result = Obj.merge(a, b);\n *\n * assert.deepStrictEqual(result, { a: 0, b: 1, c: 0 });\n * ```\n *\n * <!-- /doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->\n *\n * @param records - The records to merge\n * @returns A new record with all properties merged\n */\n export const merge = <const Records extends readonly UnknownRecord[]>(\n ...records: Records\n ): TsDataForgeInternals.MergeAll<Records> =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(records.flatMap((r) => Object.entries(r))) as never;\n\n /**\n * Deeply picks a nested property from an object along the specified key path.\n * Supports both direct and curried usage.\n *\n * @example\n *\n * ```ts\n * const data = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 } as const;\n *\n * // Direct usage\n * const result = Obj.deepPick(data, ['a', 'b', 'c']);\n *\n * assert.deepStrictEqual(result, { a: { b: { c: 1 } } });\n *\n * // Curried usage with pipe\n * const pickAB = Obj.deepPick(['a', 'b']);\n *\n * const result2 = pipe(data).map(pickAB).value;\n *\n * assert.deepStrictEqual(result2, { a: { b: { c: 1, d: 2 } } });\n * ```\n *\n * @template R - The type of the input record\n * @template Path - The key path tuple\n * @param record - The source record\n * @param path - A readonly tuple of keys representing the nested path\n * @returns A new record containing only the nested property at the path\n */\n export function deepPick<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(record: R, path: Path): DeepPick<R, Path>;\n\n // Curried version\n export function deepPick<const Path extends readonly (string | number)[]>(\n path: Path,\n ): <const R extends UnknownRecord>(record: R) => DeepPick<R, Path>;\n\n export function deepPick<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(\n ...args: readonly [record: R, path: Path] | readonly [path: Path]\n ): DeepPick<R, Path> | ((record: R) => DeepPick<R, Path>) {\n switch (args.length) {\n case 2: {\n const [record, path] = args;\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n deepPickImpl(record, path) as never\n );\n }\n\n case 1: {\n const [path] = args;\n\n return (record: R) => deepPick(record, path);\n }\n }\n }\n\n /**\n * Deeply omits a nested property from an object along the specified key path.\n * Supports both direct and curried usage.\n *\n * @example\n *\n * ```ts\n * const data = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 } as const;\n *\n * // Direct usage\n * const result = Obj.deepOmit(data, ['a', 'b', 'c']);\n *\n * assert.deepStrictEqual(result, { a: { b: { d: 2 }, e: 3 }, f: 4 });\n *\n * // Curried usage with pipe\n * const omitAB = Obj.deepOmit(['a', 'b']);\n *\n * const result2 = pipe(data).map(omitAB).value;\n *\n * assert.deepStrictEqual(result2, { a: { e: 3 }, f: 4 });\n * ```\n *\n * @template R - The type of the input record\n * @template Path - The key path tuple\n * @param record - The source record\n * @param path - A readonly tuple of keys representing the nested path to omit\n * @returns A new record with the nested property at the path removed\n */\n export function deepOmit<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(record: R, path: Path): DeepOmit<R, Path>;\n\n // Curried version\n export function deepOmit<const Path extends readonly (string | number)[]>(\n path: Path,\n ): <const R extends UnknownRecord>(record: R) => DeepOmit<R, Path>;\n\n export function deepOmit<\n const R extends UnknownRecord,\n const Path extends readonly (string | number)[],\n >(\n ...args: readonly [record: R, path: Path] | readonly [path: Path]\n ): DeepOmit<R, Path> | ((record: R) => DeepOmit<R, Path>) {\n switch (args.length) {\n case 2: {\n const [record, path] = args;\n\n return (\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n deepOmitImpl(record, path) as never\n );\n }\n\n case 1: {\n const [path] = args;\n\n return (record: R) => deepOmit(record, path);\n }\n }\n }\n}\n\nconst deepPickImpl = (\n record: UnknownRecord,\n path: readonly (string | number)[],\n): UnknownRecord => {\n if (!Arr.isNonEmpty(path)) return record;\n\n const head = path[0];\n\n if (!hasKey(record, head)) return {};\n\n const value = record[head];\n\n const tail = path.slice(1);\n\n if (!Arr.isNonEmpty(tail)) return { [head]: value };\n\n if (!isRecord(value)) return { [head]: {} };\n\n return {\n [head]: deepPickImpl(value, tail),\n };\n};\n\nconst deepOmitImpl = (\n record: UnknownRecord,\n path: readonly (string | number)[],\n): UnknownRecord => {\n if (!Arr.isNonEmpty(path)) return record;\n\n const head = path[0];\n\n if (!hasKey(record, head)) return record;\n\n const tail = path.slice(1);\n\n if (!Arr.isNonEmpty(tail)) {\n return Object.fromEntries(\n Object.entries(record).filter(([k]) => k !== head),\n );\n }\n\n const value = record[head];\n\n if (!isRecord(value)) return record;\n\n return {\n ...record,\n [head]: deepOmitImpl(value, tail),\n };\n};\n\n/**\n * @internal\n * Internal type utilities for the Obj module.\n */\ndeclare namespace TsDataForgeInternals {\n type RecursionLimit = 20;\n\n /** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */\n export type EntriesToObject<\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n > = Readonly<EntriesToObjectImpl<{}, Entries>>;\n\n /** @internal */\n type EntriesToObjectImpl<\n R,\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n > =\n TypeEq<Entries['length'], 0> extends true\n ? R\n : EntriesToObjectImpl<\n R & ReadonlyRecord<Entries[0][0], Entries[0][1]>,\n List.Tail<Entries>\n >;\n\n /**\n * - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`\n * - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |\n * 'b' | 'c' | 'x' | 'y' | 'z'`\n *\n * @note To handle the second example above, recursion needs to be performed on infinite-length Entries,\n * but since the timing to stop cannot be determined, a recursion limit is set.\n */\n export type KeysOfEntries<\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n > = KeysOfEntriesImpl<never, Entries, RecursionLimit>;\n\n type KeysOfEntriesImpl<\n K,\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n RemainingNumRecursions extends number,\n > =\n TypeEq<RemainingNumRecursions, 0> extends true\n ? K\n : TypeEq<Entries['length'], 0> extends true\n ? K\n : KeysOfEntriesImpl<\n K | Entries[0][0],\n List.Tail<Entries>,\n Decrement<RemainingNumRecursions>\n >;\n\n export type ValuesOfEntries<\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n > = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;\n\n type ValuesOfEntriesImpl<\n K,\n Entries extends readonly (readonly [PropertyKey, unknown])[],\n RemainingNumRecursions extends number,\n > =\n TypeEq<RemainingNumRecursions, 0> extends true\n ? K\n : TypeEq<Entries['length'], 0> extends true\n ? K\n : ValuesOfEntriesImpl<\n K | Entries[0][1],\n List.Tail<Entries>,\n Decrement<RemainingNumRecursions>\n >;\n\n export type PartialIfKeyIsUnion<K, T> =\n IsUnion<K> extends true ? Partial<T> : T;\n\n /**\n * Merges two object types where keys in B override keys in A, preserving optional modifiers.\n *\n * This implementation uses a sophisticated technique to preserve optional property modifiers (`?`)\n * during the merge operation, which would otherwise be lost in a naive mapped type implementation.\n *\n * ## Core Technique: Optional Property Detection\n *\n * Uses `{} extends Pick<T, K>` to determine if a property is optional:\n * - **Required property**: `Pick<T, 'x'>` = `{ x: number }` → `{}` does NOT extend it (false)\n * - **Optional property**: `Pick<T, 'y'>` = `{ y?: string }` → `{}` DOES extend it (true)\n *\n * This works because `{}` (empty object) is assignable to objects with only optional properties\n * but not to objects with required properties.\n *\n * ## Implementation Strategy\n *\n * The type is constructed as an intersection of five mapped types:\n *\n * 1. **Required properties from B** - Properties in B that are required (override A completely)\n * 2. **Optional properties from B (not in A)** - New optional properties from B\n * 3. **Optional properties from B (in A)** - Union of A[K] | B[K] to preserve both possibilities\n * 4. **Required properties only in A** - Properties in A but not in B that are required\n * 5. **Optional properties only in A** - Properties in A but not in B that are optional (with `?` modifier)\n *\n * Finally, the intersection is flattened using an optional-preserving identity mapping that\n * re-applies the optional detection logic to maintain the `?` modifiers in the final type.\n *\n * @example\n * ```ts\n * type A = Readonly<{ x: number; y?: string }>;\n *\n * type B = Readonly<{ y?: number; z?: boolean }>;\n *\n * type Result = MergeTwo<A, B>;\n * // Result: Readonly<{ x: number; y?: string | number; z?: boolean }>\n * ```\n */\n // transformer-ignore-next-line\n type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = {\n // 1. Required properties from B (override A completely)\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n readonly [K in keyof B as {} extends StrictPick<B, K> ? never : K]: B[K];\n } & {\n // 2. Optional properties from B that are NOT in A\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in keyof B as {} extends StrictPick<B, K>\n ? K extends keyof A\n ? never\n : K\n : never\n ]?: B[K];\n } & {\n // 3. Optional properties from B that ARE in A (create union)\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in keyof B as {} extends StrictPick<B, K>\n ? K extends keyof A\n ? K\n : never\n : never\n ]?: K extends keyof A ? A[K] | B[K] : never;\n } & {\n // 4. Required properties only in A (not overridden by B)\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in RelaxedExclude<keyof A, keyof B> as {} extends StrictPick<A, K>\n ? never\n : K\n ]: A[K];\n } & {\n // 5. Optional properties only in A (not overridden by B)\n readonly [\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n K in RelaxedExclude<keyof A, keyof B> as {} extends StrictPick<A, K>\n ? K\n : never\n ]?: A[K];\n } extends infer O\n ? Readonly<\n {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n [K in keyof O as {} extends StrictPick<O, K> ? never : K]: O[K];\n } & {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n [K in keyof O as {} extends StrictPick<O, K> ? K : never]?: O[K];\n }\n >\n : never;\n\n /** Sequentially merges a tuple of object types from left to right. */\n export type MergeAll<\n Records extends readonly UnknownRecord[],\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n Acc extends UnknownRecord = {},\n > =\n IsFixedLengthList<Records> extends false\n ? ArrayElement<Records>\n : Records extends readonly [\n infer First extends UnknownRecord,\n ...infer Rest extends readonly UnknownRecord[],\n ]\n ? MergeAll<Rest, MergeTwo<Acc, First>>\n : Acc;\n}\n"],"names":["Obj","Arr.isNonEmpty"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fast-deep-equal.d.mts","sourceRoot":"","sources":["../../src/others/fast-deep-equal.mts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,KAAM,CAAC,KAAK,CAAC,KAAG,OAuF9C,CAAC"}
1
+ {"version":3,"file":"fast-deep-equal.d.mts","sourceRoot":"","sources":["../../src/others/fast-deep-equal.mts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,KAAM,CAAC,KAAK,CAAC,KAAG,OAyF9C,CAAC"}
@@ -20,12 +20,12 @@ const fastDeepEqual = (a, b) => {
20
20
  return false;
21
21
  }
22
22
  if (isMap(a)) {
23
- return isMap(b) && a.size === b.size && Array.from(a.entries()).every(
23
+ return isMap(b) && a.size === b.size && a.entries().every(
24
24
  ([key, value]) => b.has(key) && fastDeepEqual(value, b.get(key))
25
25
  );
26
26
  }
27
27
  if (isSet(a)) {
28
- return isSet(b) && a.size === b.size && Array.from(a.entries()).every(([value]) => b.has(value));
28
+ return isSet(b) && a.size === b.size && a.entries().every(([value]) => b.has(value));
29
29
  }
30
30
  if (isTypedArray(a)) {
31
31
  return isTypedArray(b) && a.length === b.length && a.every((value, index) => value === b[index]);
@@ -1 +1 @@
1
- {"version":3,"file":"fast-deep-equal.mjs","sources":["../../src/others/fast-deep-equal.mts"],"sourcesContent":["import { isMap, isRegExp, isSet, isTypedArray } from '@sindresorhus/is';\nimport { hasKey, isRecord } from '../guard/index.mjs';\n\n/**\n * The fastest deep equal with ES6 Map, Set and Typed arrays support.\n * Checks equality of Date and RegExp objects by value.\n *\n * Forked from https://github.com/epoberezkin/fast-deep-equal/blob/v3.1.3/src/index.jst\n */\nexport const fastDeepEqual = <T,>(a: T, b: T): boolean => {\n if (a === b) {\n return true;\n }\n\n if (typeof a !== typeof b) {\n return false;\n }\n\n // Arrays are handled before `isRecord`, which excludes them.\n if (Array.isArray(a)) {\n return (\n Array.isArray(b) &&\n a.constructor === b.constructor &&\n a.length === b.length &&\n a.every((ai, index) => fastDeepEqual(ai, b[index]))\n );\n }\n\n if (isRecord(a)) {\n if (!isRecord(b)) {\n return false;\n }\n\n if (a.constructor !== b.constructor) {\n return false;\n }\n\n if (isMap(a)) {\n return (\n isMap(b) &&\n a.size === b.size &&\n Array.from(a.entries()).every(\n ([key, value]) => b.has(key) && fastDeepEqual(value, b.get(key)),\n )\n );\n }\n\n if (isSet(a)) {\n return (\n isSet(b) &&\n a.size === b.size &&\n Array.from(a.entries()).every(([value]) => b.has(value))\n );\n }\n\n if (isTypedArray(a)) {\n return (\n isTypedArray(b) &&\n a.length === b.length &&\n a.every((value, index) => value === b[index])\n );\n }\n\n if (isRegExp(a)) {\n return isRegExp(b) && a.source === b.source && a.flags === b.flags;\n }\n\n if (a.valueOf !== Object.prototype.valueOf) {\n return a.valueOf() === b.valueOf();\n }\n\n if (a.toString !== Object.prototype.toString) {\n return a.toString() === b.toString();\n }\n\n const aKeys: readonly string[] = Object.keys(a);\n\n const bKeys: readonly string[] = Object.keys(b);\n\n return (\n aKeys.length === bKeys.length &&\n aKeys.every(\n (key) =>\n hasKey(b, key) &&\n // React-specific: avoid traversing React elements' _owner.\n // _owner contains circular references\n // and is not needed when comparing the actual elements (and not their owners)\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n !(key === '_owner' && a['$$typeof']) &&\n fastDeepEqual(a[key], b[key]),\n )\n );\n }\n\n // true if both NaN, false otherwise\n return Number.isNaN(a) && Number.isNaN(b);\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fast-deep-equal.mjs","sources":["../../src/others/fast-deep-equal.mts"],"sourcesContent":["import { isMap, isRegExp, isSet, isTypedArray } from '@sindresorhus/is';\nimport { hasKey, isRecord } from '../guard/index.mjs';\n\n/**\n * The fastest deep equal with ES6 Map, Set and Typed arrays support.\n * Checks equality of Date and RegExp objects by value.\n *\n * Forked from https://github.com/epoberezkin/fast-deep-equal/blob/v3.1.3/src/index.jst\n */\nexport const fastDeepEqual = <T,>(a: T, b: T): boolean => {\n if (a === b) {\n return true;\n }\n\n if (typeof a !== typeof b) {\n return false;\n }\n\n // Arrays are handled before `isRecord`, which excludes them.\n if (Array.isArray(a)) {\n return (\n Array.isArray(b) &&\n a.constructor === b.constructor &&\n a.length === b.length &&\n a.every((ai, index) => fastDeepEqual(ai, b[index]))\n );\n }\n\n if (isRecord(a)) {\n if (!isRecord(b)) {\n return false;\n }\n\n if (a.constructor !== b.constructor) {\n return false;\n }\n\n if (isMap(a)) {\n return (\n isMap(b) &&\n a.size === b.size &&\n a\n .entries()\n .every(\n ([key, value]) => b.has(key) && fastDeepEqual(value, b.get(key)),\n )\n );\n }\n\n if (isSet(a)) {\n return (\n isSet(b) &&\n a.size === b.size &&\n a.entries().every(([value]) => b.has(value))\n );\n }\n\n if (isTypedArray(a)) {\n return (\n isTypedArray(b) &&\n a.length === b.length &&\n a.every((value, index) => value === b[index])\n );\n }\n\n if (isRegExp(a)) {\n return isRegExp(b) && a.source === b.source && a.flags === b.flags;\n }\n\n if (a.valueOf !== Object.prototype.valueOf) {\n return a.valueOf() === b.valueOf();\n }\n\n if (a.toString !== Object.prototype.toString) {\n return a.toString() === b.toString();\n }\n\n const aKeys: readonly string[] = Object.keys(a);\n\n const bKeys: readonly string[] = Object.keys(b);\n\n return (\n aKeys.length === bKeys.length &&\n aKeys.every(\n (key) =>\n hasKey(b, key) &&\n // React-specific: avoid traversing React elements' _owner.\n // _owner contains circular references\n // and is not needed when comparing the actual elements (and not their owners)\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n !(key === '_owner' && a['$$typeof']) &&\n fastDeepEqual(a[key], b[key]),\n )\n );\n }\n\n // true if both NaN, false otherwise\n return Number.isNaN(a) && Number.isNaN(b);\n};\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-data-forge",
3
- "version": "14.0.1",
3
+ "version": "14.1.0",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript",
@@ -36,7 +36,7 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "@sindresorhus/is": "^8.1.0",
39
- "ts-type-forge": "~9.1.1"
39
+ "ts-type-forge": "~9.1.3"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@emotion/react": "11.14.0",
@@ -8,7 +8,11 @@ import {
8
8
  import { expectType } from '../../expect-type.mjs';
9
9
  import { asUint32 } from '../../number/index.mjs';
10
10
  import { type SizeType } from '../../types.mjs';
11
- import { asMinLengthArray } from './array-utils-length-bounded-array-cast.mjs';
11
+ import {
12
+ asBoundedLengthArray,
13
+ asFixedLengthArray,
14
+ asMinLengthArray,
15
+ } from './array-utils-length-bounded-array-cast.mjs';
12
16
  import {
13
17
  set,
14
18
  toFilled,
@@ -408,10 +412,11 @@ describe('Arr modifications', () => {
408
412
 
409
413
  /* `Arr.set` / `Arr.toUpdated` across the input shapes the positional
410
414
  `ConstrainedList.SetAt` annotation has to cope with; the suite previously
411
- covered only the plain-tuple case. Written as an unexported-by-value function
412
- so the assertions get real overload resolution — it is never called, and the
413
- branded shapes have no runtime representation to build. */
414
- export const setTypeChecks = (
415
+ covered only the plain-tuple case. Written as a function taking each shape as
416
+ a parameter so the assertions get real overload resolution against the
417
+ declared type rather than against whatever a literal happens to infer to; the
418
+ test below feeds it values built with the `as*` casts. */
419
+ const setTypeChecks = (
415
420
  shapeTuple: readonly [1, 2, 3],
416
421
  shapeArray: readonly number[],
417
422
  shapeMutableArray: readonly number[],
@@ -487,3 +492,19 @@ export const setTypeChecks = (
487
492
 
488
493
  expectType<typeof _updatedUnion, readonly [number, 2, number]>('=');
489
494
  };
495
+
496
+ test('set / toUpdated type-level checks', () => {
497
+ const strings = ['a', 'b', 'c'] as const;
498
+
499
+ setTypeChecks(
500
+ [1, 2, 3],
501
+ [1, 2, 3],
502
+ [1, 2, 3],
503
+ asMinLengthArray(3, strings),
504
+ asBoundedLengthArray(2, 5, strings),
505
+ asFixedLengthArray(3, strings),
506
+ asMinLengthArray(3, [1, 2, 3, 4, 5] as const),
507
+ 0,
508
+ 1,
509
+ );
510
+ });
@@ -14,8 +14,26 @@ import {
14
14
  asMaxLengthArray,
15
15
  asMinLengthArray,
16
16
  } from './array-utils-length-bounded-array-cast.mjs';
17
- import { toFilled, toRangeFilled } from './array-utils-modification.mjs';
18
- import { map, toReversed, toSorted } from './array-utils-transformation.mjs';
17
+ import {
18
+ toFilled,
19
+ toInserted,
20
+ toPushed,
21
+ toRangeFilled,
22
+ toRemoved,
23
+ toUnshifted,
24
+ } from './array-utils-modification.mjs';
25
+ import { skip, skipLast, take, takeLast } from './array-utils-slicing.mjs';
26
+ import {
27
+ concat,
28
+ filter,
29
+ filterNot,
30
+ map,
31
+ toReversed,
32
+ toSorted,
33
+ toSortedBy,
34
+ uniq,
35
+ uniqBy,
36
+ } from './array-utils-transformation.mjs';
19
37
 
20
38
  /**
21
39
  * Invariant-based coverage for the array -> array transforms.
@@ -31,12 +49,14 @@ import { map, toReversed, toSorted } from './array-utils-transformation.mjs';
31
49
  * 1. **Length** — the result reports the same `length` as the input.
32
50
  * 2. **Bounds** — a length brand on the input survives onto the result.
33
51
  * 3. **Generic context** — from a caller that is itself generic over the
34
- * array, the result is assignable to the caller's own homomorphic mapping.
52
+ * array, the result is assignable to the caller's own annotation.
35
53
  *
36
- * Property 3 is the one with no coverage before this file, and is what the
37
- * `Arr.map` regression fixed in this PR violated: a conditional return type a
38
- * generic `Ar` cannot decide stays deferred, and its brand-carrying branch is
39
- * then not assignable to the caller's mapping.
54
+ * Property 3 is the one that keeps regressing, and the one a per-combination
55
+ * table cannot express: a conditional a generic `Ar` cannot decide stays
56
+ * deferred, and a deferred conditional carrying a brand-intersection branch is
57
+ * not an array type at all — so the result has no `entries()`, is not
58
+ * assignable to the caller's annotation, and in the worst case the bound
59
+ * arithmetic behind the brand exceeds the instantiation limit.
40
60
  */
41
61
 
42
62
  // The sample inputs. Between them they cover the axes: empty / singleton /
@@ -71,15 +91,15 @@ const exactLength: FixedLengthArray<3, number> = asFixedLengthArray(
71
91
  * Property 3 — generic context.
72
92
  *
73
93
  * Each of these is an assertion by construction: the annotated return type is
74
- * the caller's own homomorphic mapping, so the declaration only compiles while
94
+ * what the caller is entitled to expect, so the declaration only compiles while
75
95
  * the transform reports something assignable to it. There is nothing to run.
76
96
  *
77
- * Only the transforms that satisfy this today are listed. `toSorted`,
78
- * `toSortedBy`, `toReversed`, `toUpdated`, `tail`, `butLast` and `zip` do not
79
- * yet — see the PR description for why each one resists the same fix. Add them
80
- * here as they are fixed; that is what makes this list the coverage record.
97
+ * This list is the coverage record. Every array -> array transform that
98
+ * resolves under a generic array parameter appears here; the ones that do not
99
+ * are listed at the bottom of this file, with the reason.
81
100
  */
82
101
 
102
+ // Element-replacing transforms report the caller's own homomorphic mapping.
83
103
  const mapInGenericContext = <const T extends readonly number[]>(
84
104
  xs: T,
85
105
  ): Readonly<{ [K in keyof T]: string }> => map(xs, String);
@@ -100,6 +120,85 @@ const toRangeFilledInGenericContext = <const T extends readonly number[]>(
100
120
  xs: T,
101
121
  ): Readonly<{ [K in keyof T]: number }> => toRangeFilled(xs, 0, [0, 1]);
102
122
 
123
+ // Reordering transforms keep the elements, so the caller is entitled to an
124
+ // array of them.
125
+ const toReversedInGenericContext = <const T extends readonly number[]>(
126
+ xs: T,
127
+ ): readonly T[number][] => toReversed(xs);
128
+
129
+ const toSortedInGenericContext = <const T extends readonly number[]>(
130
+ xs: T,
131
+ ): readonly T[number][] => toSorted(xs, (a, b) => a - b);
132
+
133
+ // Numbers sort without a comparator. This is the overload that makes it
134
+ // optional, which a generic caller could not reach at all while the parameter
135
+ // list was itself a conditional type.
136
+ const toSortedDefaultInGenericContext = <const T extends readonly number[]>(
137
+ xs: T,
138
+ ): readonly T[number][] => toSorted(xs);
139
+
140
+ const toSortedNonNumberInGenericContext = <const T extends readonly string[]>(
141
+ xs: T,
142
+ ): readonly T[number][] => toSorted(xs, (a, b) => a.localeCompare(b));
143
+
144
+ const toSortedByInGenericContext = <const T extends readonly number[]>(
145
+ xs: T,
146
+ ): readonly T[number][] => toSortedBy(xs, (n) => n);
147
+
148
+ // Shortening transforms lose the length but keep the element type.
149
+ const takeInGenericContext = <const T extends readonly number[]>(
150
+ xs: T,
151
+ ): readonly T[number][] => take(xs, 2);
152
+
153
+ const takeLastInGenericContext = <const T extends readonly number[]>(
154
+ xs: T,
155
+ ): readonly T[number][] => takeLast(xs, 2);
156
+
157
+ const skipInGenericContext = <const T extends readonly number[]>(
158
+ xs: T,
159
+ ): readonly T[number][] => skip(xs, 2);
160
+
161
+ const skipLastInGenericContext = <const T extends readonly number[]>(
162
+ xs: T,
163
+ ): readonly T[number][] => skipLast(xs, 2);
164
+
165
+ const toRemovedInGenericContext = <const T extends readonly number[]>(
166
+ xs: T,
167
+ ): readonly T[number][] => toRemoved(xs, 0);
168
+
169
+ const filterInGenericContext = <const T extends readonly number[]>(
170
+ xs: T,
171
+ ): readonly T[number][] => filter(xs, (n) => n > 0);
172
+
173
+ const filterNotInGenericContext = <const T extends readonly number[]>(
174
+ xs: T,
175
+ ): readonly T[number][] => filterNot(xs, (n) => n > 0);
176
+
177
+ const uniqInGenericContext = <const T extends readonly number[]>(
178
+ xs: T,
179
+ ): readonly T[number][] => uniq(xs);
180
+
181
+ const uniqByInGenericContext = <const T extends readonly number[]>(
182
+ xs: T,
183
+ ): readonly T[number][] => uniqBy(xs, (n) => n);
184
+
185
+ // Lengthening transforms widen the element type by whatever was added.
186
+ const toPushedInGenericContext = <const T extends readonly number[]>(
187
+ xs: T,
188
+ ): readonly (T[number] | 'x')[] => toPushed(xs, 'x');
189
+
190
+ const toUnshiftedInGenericContext = <const T extends readonly number[]>(
191
+ xs: T,
192
+ ): readonly (T[number] | 'x')[] => toUnshifted(xs, 'x');
193
+
194
+ const toInsertedInGenericContext = <const T extends readonly number[]>(
195
+ xs: T,
196
+ ): readonly (T[number] | 'x')[] => toInserted(xs, 0, 'x');
197
+
198
+ const concatInGenericContext = <const T extends readonly number[]>(
199
+ xs: T,
200
+ ): readonly T[number][] => concat(xs, xs);
201
+
103
202
  describe('Arr shape invariants', () => {
104
203
  // The type-level assertions below are checked by `tsc`; this pins the same
105
204
  // property at runtime, so a transform that silently drops or adds an element
@@ -107,19 +206,20 @@ describe('Arr shape invariants', () => {
107
206
  test('every shape-preserving transform keeps the length at runtime', () => {
108
207
  const input = [3, 1, 2] as const;
109
208
 
110
- assert.deepStrictEqual<FixedLengthTuple<5, 3>>(
209
+ assert.deepStrictEqual<FixedLengthTuple<6, 3>>(
111
210
  [
112
211
  map(input, String).length,
113
212
  toFilled(input, 0).length,
114
213
  toRangeFilled(input, 0, [1, 2]).length,
115
214
  toSorted(input).length,
215
+ toSortedBy(input, (n) => n).length,
116
216
  toReversed(input).length,
117
217
  ] as const,
118
- [3, 3, 3, 3, 3] as const,
218
+ [3, 3, 3, 3, 3, 3] as const,
119
219
  );
120
220
  });
121
221
 
122
- test('the generic-context callers agree with their annotations', () => {
222
+ test('the element-replacing callers agree with their annotations', () => {
123
223
  const input = [3, 1, 2] as const;
124
224
 
125
225
  assert.deepStrictEqual<FixedLengthTuple<3, string>>(
@@ -147,6 +247,105 @@ describe('Arr shape invariants', () => {
147
247
  [0, 1, 2],
148
248
  );
149
249
  });
250
+
251
+ test('the reordering callers agree with their annotations', () => {
252
+ const input = [3, 1, 2] as const;
253
+
254
+ assert.deepStrictEqual<readonly number[]>(
255
+ toReversedInGenericContext(input),
256
+ [2, 1, 3],
257
+ );
258
+
259
+ assert.deepStrictEqual<readonly number[]>(
260
+ toSortedInGenericContext(input),
261
+ [1, 2, 3],
262
+ );
263
+
264
+ assert.deepStrictEqual<readonly number[]>(
265
+ toSortedDefaultInGenericContext(input),
266
+ [1, 2, 3],
267
+ );
268
+
269
+ assert.deepStrictEqual<readonly string[]>(
270
+ toSortedNonNumberInGenericContext(['c', 'a', 'b'] as const),
271
+ ['a', 'b', 'c'],
272
+ );
273
+
274
+ assert.deepStrictEqual<readonly number[]>(
275
+ toSortedByInGenericContext(input),
276
+ [1, 2, 3],
277
+ );
278
+ });
279
+
280
+ test('the shortening callers agree with their annotations', () => {
281
+ const input = [3, 1, 2] as const;
282
+
283
+ assert.deepStrictEqual<readonly number[]>(
284
+ takeInGenericContext(input),
285
+ [3, 1],
286
+ );
287
+
288
+ assert.deepStrictEqual<readonly number[]>(
289
+ takeLastInGenericContext(input),
290
+ [1, 2],
291
+ );
292
+
293
+ assert.deepStrictEqual<readonly number[]>(skipInGenericContext(input), [2]);
294
+
295
+ assert.deepStrictEqual<readonly number[]>(
296
+ skipLastInGenericContext(input),
297
+ [3],
298
+ );
299
+
300
+ assert.deepStrictEqual<readonly number[]>(
301
+ toRemovedInGenericContext(input),
302
+ [1, 2],
303
+ );
304
+
305
+ assert.deepStrictEqual<readonly number[]>(
306
+ filterInGenericContext(input),
307
+ [3, 1, 2],
308
+ );
309
+
310
+ assert.deepStrictEqual<readonly number[]>(
311
+ filterNotInGenericContext(input),
312
+ [],
313
+ );
314
+
315
+ assert.deepStrictEqual<readonly number[]>(
316
+ uniqInGenericContext([1, 1, 2] as const),
317
+ [1, 2],
318
+ );
319
+
320
+ assert.deepStrictEqual<readonly number[]>(
321
+ uniqByInGenericContext([1, 1, 2] as const),
322
+ [1, 2],
323
+ );
324
+ });
325
+
326
+ test('the lengthening callers agree with their annotations', () => {
327
+ const input = [3, 1, 2] as const;
328
+
329
+ assert.deepStrictEqual<readonly (number | string)[]>(
330
+ toPushedInGenericContext(input),
331
+ [3, 1, 2, 'x'],
332
+ );
333
+
334
+ assert.deepStrictEqual<readonly (number | string)[]>(
335
+ toUnshiftedInGenericContext(input),
336
+ ['x', 3, 1, 2],
337
+ );
338
+
339
+ assert.deepStrictEqual<readonly (number | string)[]>(
340
+ toInsertedInGenericContext(input),
341
+ ['x', 3, 1, 2],
342
+ );
343
+
344
+ assert.deepStrictEqual<readonly number[]>(
345
+ concatInGenericContext(input),
346
+ [3, 1, 2, 3, 1, 2],
347
+ );
348
+ });
150
349
  });
151
350
 
152
351
  // `map` — property 1 (length) across every unbranded sample.
@@ -235,8 +434,7 @@ describe('Arr shape invariants', () => {
235
434
  expectType<MinLengthOf<typeof _c>, MinLengthOf<typeof lowerBounded>>('=');
236
435
  }
237
436
 
238
- // `toSorted` — properties 1 and 2. Sorting neither adds nor drops elements, so
239
- // it is held to the same contract even though it is not fixed for property 3.
437
+ // `toSorted` — properties 1 and 2. Sorting neither adds nor drops elements.
240
438
  {
241
439
  const _a = toSorted(fixedTuple);
242
440
 
@@ -261,6 +459,27 @@ describe('Arr shape invariants', () => {
261
459
  expectType<MaxLengthOf<typeof _e>, MaxLengthOf<typeof bounded>>('=');
262
460
  }
263
461
 
462
+ // `toSortedBy` — properties 1 and 2.
463
+ {
464
+ const _a = toSortedBy(fixedTuple, (n) => n);
465
+
466
+ const _b = toSortedBy(plainArray, (n) => n);
467
+
468
+ const _c = toSortedBy(lowerBounded, (n) => n);
469
+
470
+ const _d = toSortedBy(bounded, (n) => n);
471
+
472
+ expectType<(typeof _a)['length'], (typeof fixedTuple)['length']>('=');
473
+
474
+ expectType<(typeof _b)['length'], (typeof plainArray)['length']>('=');
475
+
476
+ expectType<MinLengthOf<typeof _c>, MinLengthOf<typeof lowerBounded>>('=');
477
+
478
+ expectType<MinLengthOf<typeof _d>, MinLengthOf<typeof bounded>>('=');
479
+
480
+ expectType<MaxLengthOf<typeof _d>, MaxLengthOf<typeof bounded>>('=');
481
+ }
482
+
264
483
  // `toReversed` — properties 1 and 2. Reversal permutes, so the length and the
265
484
  // bounds are exactly what must not move.
266
485
  {
@@ -282,3 +501,26 @@ describe('Arr shape invariants', () => {
282
501
 
283
502
  expectType<MaxLengthOf<typeof _d>, MaxLengthOf<typeof bounded>>('=');
284
503
  }
504
+
505
+ /**
506
+ * The transforms that do **not** resolve under a generic array parameter, and
507
+ * therefore have no property-3 entry above:
508
+ *
509
+ * | transform | reports | symptom under a generic `Ar` |
510
+ * | :------------------ | :---------------------- | :--------------------------- |
511
+ * | `tail` / `butLast` | `ConstrainedList.Tail` | TS2590 |
512
+ * | `zip` | `ConstrainedList.Zip` | TS2589, and no `entries()` |
513
+ * | `set` / `toUpdated` | `ConstrainedList.SetAt` | TS2589 |
514
+ *
515
+ * The cause is the same in all three, and it is upstream. Their brand branch
516
+ * does arithmetic on the input's own bounds (`SubLength`, `SmallerLength`), and
517
+ * that arithmetic goes through `MakeTuple`. For a concrete branded array the
518
+ * bound is a single number and the expansion is cheap; for a type parameter it
519
+ * is the whole `SupportedLength` union, which `MakeTuple` distributes over.
520
+ *
521
+ * `map`, `toFilled` and `toRangeFilled` were fixable in 14.0.1 precisely
522
+ * because `ChangeArrayElement`'s brand branch does no such arithmetic. The
523
+ * `UnknownBrand`-keyed overload split that fixed them does not transfer: the
524
+ * constrained overload makes the checker attempt that arithmetic at every call
525
+ * site, generic or not.
526
+ */