ts-data-forge 6.6.0 → 6.7.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.
@@ -49,7 +49,7 @@ export declare namespace Obj {
49
49
  * @returns `true` if the records are shallowly equal according to the
50
50
  * equality function, `false` otherwise
51
51
  */
52
- export const shallowEq: (a: UnknownRecord, b: UnknownRecord, eq?: (x: unknown, y: unknown) => boolean) => boolean;
52
+ const shallowEq: (a: UnknownRecord, b: UnknownRecord, eq?: (x: unknown, y: unknown) => boolean) => boolean;
53
53
  /**
54
54
  * Creates a new record that contains only the specified keys from the source
55
55
  * record. This function supports both direct usage and curried form for
@@ -93,8 +93,8 @@ export declare namespace Obj {
93
93
  * @param keys - A readonly array of keys to include in the result
94
94
  * @returns A new record containing only the specified keys and their values
95
95
  */
96
- export function pick<const R extends UnknownRecord, const Keys extends readonly (keyof R)[]>(record: R, keys: Keys): Pick<R, ArrayElement<Keys>>;
97
- export function pick<const Keys extends readonly PropertyKey[]>(keys: Keys): <const R extends UnknownRecord>(record: R) => RelaxedPick<R, ArrayElement<Keys>>;
96
+ function pick<const R extends UnknownRecord, const Keys extends readonly (keyof R)[]>(record: R, keys: Keys): Pick<R, ArrayElement<Keys>>;
97
+ function pick<const Keys extends readonly PropertyKey[]>(keys: Keys): <const R extends UnknownRecord>(record: R) => RelaxedPick<R, ArrayElement<Keys>>;
98
98
  /**
99
99
  * Creates a new record that excludes the specified keys from the source
100
100
  * record. This function supports both direct usage and curried form for
@@ -140,8 +140,8 @@ export declare namespace Obj {
140
140
  * @param keys - A readonly array of keys to exclude from the result
141
141
  * @returns A new record containing all properties except the specified keys
142
142
  */
143
- export function omit<const R extends UnknownRecord, const Keys extends readonly (keyof R)[]>(record: R, keys: Keys): Omit<R, ArrayElement<Keys>>;
144
- export function omit<const Keys extends readonly PropertyKey[]>(keys: Keys): <const R extends UnknownRecord>(record: R) => Omit<R, ArrayElement<Keys>>;
143
+ function omit<const R extends UnknownRecord, const Keys extends readonly (keyof R)[]>(record: R, keys: Keys): Omit<R, ArrayElement<Keys>>;
144
+ function omit<const Keys extends readonly PropertyKey[]>(keys: Keys): <const R extends UnknownRecord>(record: R) => Omit<R, ArrayElement<Keys>>;
145
145
  /**
146
146
  * Creates an object from an array of key-value pairs with precise TypeScript
147
147
  * typing. This is a type-safe wrapper around `Object.fromEntries` that
@@ -187,40 +187,7 @@ export declare namespace Obj {
187
187
  * @param entries - An array of readonly key-value entry tuples `[key, value]`
188
188
  * @returns An object created from the entries with precise typing
189
189
  */
190
- export const fromEntries: <const Entries extends readonly (readonly [PropertyKey, unknown])[]>(entries: Entries) => IsFixedLengthList<Entries> extends true ? TsDataForgeInternals.EntriesToObject<Entries> : TsDataForgeInternals.PartialIfKeyIsUnion<TsDataForgeInternals.KeysOfEntries<Entries>, ReadonlyRecord<TsDataForgeInternals.KeysOfEntries<Entries>, TsDataForgeInternals.ValuesOfEntries<Entries>>>;
191
- /**
192
- * @internal
193
- * Internal type utilities for the Obj module.
194
- */
195
- namespace TsDataForgeInternals {
196
- type RecursionLimit = 20;
197
- /** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */
198
- type EntriesToObject<Entries extends readonly (readonly [PropertyKey, unknown])[]> = Readonly<EntriesToObjectImpl<{}, Entries>>;
199
- /** @internal */
200
- type EntriesToObjectImpl<R, Entries extends readonly (readonly [PropertyKey, unknown])[]> = TypeEq<Entries['length'], 0> extends true ? R : EntriesToObjectImpl<R & Readonly<Record<Entries[0][0], Entries[0][1]>>, List.Tail<Entries>>;
201
- /**
202
- * - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`
203
- * - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |
204
- * 'b' | 'c' | 'x' | 'y' | 'z'`
205
- *
206
- * @note To handle the second example above, recursion needs to be performed on infinite-length Entries,
207
- * but since the timing to stop cannot be determined, a recursion limit is set.
208
- */
209
- type KeysOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = KeysOfEntriesImpl<never, Entries, RecursionLimit>;
210
- type KeysOfEntriesImpl<K, Entries extends readonly (readonly [PropertyKey, unknown])[], RemainingNumRecursions extends number> = TypeEq<RemainingNumRecursions, 0> extends true ? K : TypeEq<Entries['length'], 0> extends true ? K : KeysOfEntriesImpl<K | Entries[0][0], List.Tail<Entries>, Decrement<RemainingNumRecursions>>;
211
- type ValuesOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;
212
- type ValuesOfEntriesImpl<K, Entries extends readonly (readonly [PropertyKey, unknown])[], RemainingNumRecursions extends number> = TypeEq<RemainingNumRecursions, 0> extends true ? K : TypeEq<Entries['length'], 0> extends true ? K : ValuesOfEntriesImpl<K | Entries[0][1], List.Tail<Entries>, Decrement<RemainingNumRecursions>>;
213
- type PartialIfKeyIsUnion<K, T> = IsUnion<K> extends true ? Partial<T> : T;
214
- /** Merges two object types where keys in B override keys in A. */
215
- type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = Readonly<{
216
- [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;
217
- }>;
218
- /** Sequentially merges a tuple of object types from left to right. */
219
- type MergeAll<Records extends readonly UnknownRecord[], Acc extends UnknownRecord = {}> = Records extends readonly [
220
- infer First extends UnknownRecord,
221
- ...infer Rest extends readonly UnknownRecord[]
222
- ] ? MergeAll<Rest, MergeTwo<Acc, First>> : Acc;
223
- }
190
+ const fromEntries: <const Entries extends readonly (readonly [PropertyKey, unknown])[]>(entries: Entries) => IsFixedLengthList<Entries> extends true ? TsDataForgeInternals.EntriesToObject<Entries> : TsDataForgeInternals.PartialIfKeyIsUnion<TsDataForgeInternals.KeysOfEntries<Entries>, ReadonlyRecord<TsDataForgeInternals.KeysOfEntries<Entries>, TsDataForgeInternals.ValuesOfEntries<Entries>>>;
224
191
  /**
225
192
  * Merges multiple records into a single record using `Object.assign`.
226
193
  * Later records override properties from earlier records with the same key.
@@ -239,7 +206,87 @@ export declare namespace Obj {
239
206
  * @param records - The records to merge
240
207
  * @returns A new record with all properties merged
241
208
  */
242
- export const merge: <const Records extends readonly UnknownRecord[]>(...records: Records) => TsDataForgeInternals.MergeAll<Records>;
243
- export {};
209
+ const merge: <const Records extends readonly UnknownRecord[]>(...records: Records) => TsDataForgeInternals.MergeAll<Records>;
210
+ }
211
+ /**
212
+ * @internal
213
+ * Internal type utilities for the Obj module.
214
+ */
215
+ declare namespace TsDataForgeInternals {
216
+ type RecursionLimit = 20;
217
+ /** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */
218
+ type EntriesToObject<Entries extends readonly (readonly [PropertyKey, unknown])[]> = Readonly<EntriesToObjectImpl<{}, Entries>>;
219
+ /** @internal */
220
+ type EntriesToObjectImpl<R, Entries extends readonly (readonly [PropertyKey, unknown])[]> = TypeEq<Entries['length'], 0> extends true ? R : EntriesToObjectImpl<R & Readonly<Record<Entries[0][0], Entries[0][1]>>, List.Tail<Entries>>;
221
+ /**
222
+ * - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`
223
+ * - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |
224
+ * 'b' | 'c' | 'x' | 'y' | 'z'`
225
+ *
226
+ * @note To handle the second example above, recursion needs to be performed on infinite-length Entries,
227
+ * but since the timing to stop cannot be determined, a recursion limit is set.
228
+ */
229
+ type KeysOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = KeysOfEntriesImpl<never, Entries, RecursionLimit>;
230
+ type KeysOfEntriesImpl<K, Entries extends readonly (readonly [PropertyKey, unknown])[], RemainingNumRecursions extends number> = TypeEq<RemainingNumRecursions, 0> extends true ? K : TypeEq<Entries['length'], 0> extends true ? K : KeysOfEntriesImpl<K | Entries[0][0], List.Tail<Entries>, Decrement<RemainingNumRecursions>>;
231
+ type ValuesOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;
232
+ type ValuesOfEntriesImpl<K, Entries extends readonly (readonly [PropertyKey, unknown])[], RemainingNumRecursions extends number> = TypeEq<RemainingNumRecursions, 0> extends true ? K : TypeEq<Entries['length'], 0> extends true ? K : ValuesOfEntriesImpl<K | Entries[0][1], List.Tail<Entries>, Decrement<RemainingNumRecursions>>;
233
+ type PartialIfKeyIsUnion<K, T> = IsUnion<K> extends true ? Partial<T> : T;
234
+ /**
235
+ * Merges two object types where keys in B override keys in A, preserving optional modifiers.
236
+ *
237
+ * This implementation uses a sophisticated technique to preserve optional property modifiers (`?`)
238
+ * during the merge operation, which would otherwise be lost in a naive mapped type implementation.
239
+ *
240
+ * ## Core Technique: Optional Property Detection
241
+ *
242
+ * Uses `{} extends Pick<T, K>` to determine if a property is optional:
243
+ * - **Required property**: `Pick<T, 'x'>` = `{ x: number }` → `{}` does NOT extend it (false)
244
+ * - **Optional property**: `Pick<T, 'y'>` = `{ y?: string }` → `{}` DOES extend it (true)
245
+ *
246
+ * This works because `{}` (empty object) is assignable to objects with only optional properties
247
+ * but not to objects with required properties.
248
+ *
249
+ * ## Implementation Strategy
250
+ *
251
+ * The type is constructed as an intersection of five mapped types:
252
+ *
253
+ * 1. **Required properties from B** - Properties in B that are required (override A completely)
254
+ * 2. **Optional properties from B (not in A)** - New optional properties from B
255
+ * 3. **Optional properties from B (in A)** - Union of A[K] | B[K] to preserve both possibilities
256
+ * 4. **Required properties only in A** - Properties in A but not in B that are required
257
+ * 5. **Optional properties only in A** - Properties in A but not in B that are optional (with `?` modifier)
258
+ *
259
+ * Finally, the intersection is flattened using an optional-preserving identity mapping that
260
+ * re-applies the optional detection logic to maintain the `?` modifiers in the final type.
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * type A = { x: number; y?: string };
265
+ * type B = { y?: number; z?: boolean };
266
+ * type Result = MergeTwo<A, B>;
267
+ * // Result: { x: number; y?: string | number; z?: boolean }
268
+ * ```
269
+ */
270
+ type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = {
271
+ readonly [K in keyof B as {} extends Pick<B, K> ? never : K]: B[K];
272
+ } & {
273
+ readonly [K in keyof B as {} extends Pick<B, K> ? K extends keyof A ? never : K : never]?: B[K];
274
+ } & {
275
+ readonly [K in keyof B as {} extends Pick<B, K> ? K extends keyof A ? K : never : never]?: K extends keyof A ? A[K] | B[K] : never;
276
+ } & {
277
+ readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? never : K]: A[K];
278
+ } & {
279
+ readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? K : never]?: A[K];
280
+ } extends infer O ? Readonly<{
281
+ [K in keyof O as {} extends Pick<O, K> ? never : K]: O[K];
282
+ } & {
283
+ [K in keyof O as {} extends Pick<O, K> ? K : never]?: O[K];
284
+ }> : never;
285
+ /** Sequentially merges a tuple of object types from left to right. */
286
+ type MergeAll<Records extends readonly UnknownRecord[], Acc extends UnknownRecord = {}> = IsFixedLengthList<Records> extends false ? ArrayElement<Records> : Records extends readonly [
287
+ infer First extends UnknownRecord,
288
+ ...infer Rest extends readonly UnknownRecord[]
289
+ ] ? MergeAll<Rest, MergeTwo<Acc, First>> : Acc;
244
290
  }
291
+ export {};
245
292
  //# sourceMappingURL=object.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.mts","sourceRoot":"","sources":["../../src/object/object.mts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,yBAAiB,GAAG,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACH,MAAM,CAAC,MAAM,SAAS,GACpB,GAAG,aAAa,EAChB,GAAG,aAAa,EAChB,KAAI,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,KAAK,OAAmB,KAClD,OASF,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACH,MAAM,UAAU,IAAI,CAClB,KAAK,CAAC,CAAC,SAAS,aAAa,EAC7B,KAAK,CAAC,IAAI,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EACvC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAGtD,MAAM,UAAU,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,SAAS,WAAW,EAAE,EAC5D,IAAI,EAAE,IAAI,GACT,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,EAC/B,MAAM,EAAE,CAAC,KACN,WAAW,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAgCxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4CG;IACH,MAAM,UAAU,IAAI,CAClB,KAAK,CAAC,CAAC,SAAS,aAAa,EAC7B,KAAK,CAAC,IAAI,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EACvC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAGtD,MAAM,UAAU,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,SAAS,WAAW,EAAE,EAC5D,IAAI,EAAE,IAAI,GACT,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IA0C7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4CG;IACH,MAAM,CAAC,MAAM,WAAW,GACtB,KAAK,CAAC,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,EAElE,SAAS,OAAO,KACf,iBAAiB,CAAC,OAAO,CAAC,SAAS,IAAI,GACtC,oBAAoB,CAAC,eAAe,CAAC,OAAO,CAAC,GAC7C,oBAAoB,CAAC,mBAAmB,CACtC,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC,EAC3C,cAAc,CACZ,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC,EAC3C,oBAAoB,CAAC,eAAe,CAAC,OAAO,CAAC,CAC9C,CAG+B,CAAC;IAEvC;;;OAGG;IACH,UAAkB,oBAAoB,CAAC;QACrC,KAAK,cAAc,GAAG,EAAE,CAAC;QAEzB,mDAAmD;QACnD,KAAY,eAAe,CACzB,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAE1D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QAE/C,gBAAgB;QAChB,KAAK,mBAAmB,CACtB,CAAC,EACD,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAE5D,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,GACrC,CAAC,GACD,mBAAmB,CACjB,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAClD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CACnB,CAAC;QAER;;;;;;;WAOG;QACH,KAAY,aAAa,CACvB,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAC1D,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAEtD,KAAK,iBAAiB,CACpB,CAAC,EACD,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,EAC5D,sBAAsB,SAAS,MAAM,IAErC,MAAM,CAAC,sBAAsB,EAAE,CAAC,CAAC,SAAS,IAAI,GAC1C,CAAC,GACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,GACvC,CAAC,GACD,iBAAiB,CACf,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAClB,SAAS,CAAC,sBAAsB,CAAC,CAClC,CAAC;QAEV,KAAY,eAAe,CACzB,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,IAC1D,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;QAExD,KAAK,mBAAmB,CACtB,CAAC,EACD,OAAO,SAAS,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,EAC5D,sBAAsB,SAAS,MAAM,IAErC,MAAM,CAAC,sBAAsB,EAAE,CAAC,CAAC,SAAS,IAAI,GAC1C,CAAC,GACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,IAAI,GACvC,CAAC,GACD,mBAAmB,CACjB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAClB,SAAS,CAAC,sBAAsB,CAAC,CAClC,CAAC;QAEV,KAAY,mBAAmB,CAAC,CAAC,EAAE,CAAC,IAClC,OAAO,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAE3C,kEAAkE;QAClE,KAAK,QAAQ,CAAC,CAAC,SAAS,aAAa,EAAE,CAAC,SAAS,aAAa,IAAI,QAAQ,CAAC;aACxE,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GACvC,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,SAAS,MAAM,CAAC,GACf,CAAC,CAAC,CAAC,CAAC,GACJ,KAAK;SACZ,CAAC,CAAC;QAEH,sEAAsE;QACtE,KAAY,QAAQ,CAClB,OAAO,SAAS,SAAS,aAAa,EAAE,EAExC,GAAG,SAAS,aAAa,GAAG,EAAE,IAC5B,OAAO,SAAS,SAAS;YAC3B,MAAM,KAAK,SAAS,aAAa;YACjC,GAAG,MAAM,IAAI,SAAS,SAAS,aAAa,EAAE;SAC/C,GACG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,GACpC,GAAG,CAAC;KACT;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,MAAM,KAAK,GAAI,KAAK,CAAC,OAAO,SAAS,SAAS,aAAa,EAAE,EAClE,GAAG,SAAS,OAAO,KAClB,oBAAoB,CAAC,QAAQ,CAAC,OAAO,CAEgC,CAAC;;CAC1E"}
1
+ {"version":3,"file":"object.d.mts","sourceRoot":"","sources":["../../src/object/object.mts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"object.mjs","sources":["../../src/object/object.mts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;AAOG;AACG,IAAW;AAAjB,CAAA,UAAiB,GAAG,EAAA;AAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCG;IACU,GAAA,CAAA,SAAS,GAAG,CACvB,CAAgB,EAChB,CAAgB,EAChB,EAAA,GAA0C,MAAM,CAAC,EAAE,KACxC;QACX,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAElC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;;AAGlC,QAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;AAAE,YAAA,OAAO,KAAK;QAErD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAChD,IAAA,CAAC;IAyDD,SAAgB,IAAI,CAIlB,GAAG,IAA8D,EAAA;AAIjE,QAAA,QAAQ,IAAI,CAAC,MAAM;YACjB,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI;AAE3B,gBAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAU,IAAI,CAAC;gBAEtC;;AAEE,gBAAA,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAClD;YAEd;YAEA,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;gBAEnB,OAAO,CAAC,MAAS,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;YAC1C;;IAEJ;AA5BgB,IAAA,GAAA,CAAA,IAAI,OA4BnB;IAyDD,SAAgB,IAAI,CAIlB,GAAG,IAEwC,EAAA;AAI3C,QAAA,QAAQ,IAAI,CAAC,MAAM;YACjB,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI;AAE3B,gBAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAU,IAAI,CAAC;gBAEtC;;AAEE,gBAAA,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACnD;YAEd;YAEA,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;gBAEnB,OAAO,CAA2B,MAAU,KAAI;;oBAE9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAA6B,CAGxD;AAED,oBAAA,OAAO,MAAM;AACf,gBAAA,CAAC;YACH;;IAEJ;AAtCgB,IAAA,GAAA,CAAA,IAAI,OAsCnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CG;AACU,IAAA,GAAA,CAAA,WAAW,GAAG,CAGzB,OAAgB;;AAWhB,IAAA,MAAM,CAAC,WAAW,CAAC,OAAO,CAAU;AAkGtC;;;;;;;;;;;;;;;;;AAiBG;AACU,IAAA,GAAA,CAAA,KAAK,GAAG,CACnB,GAAG,OAAgB;;IAGnB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAU;AAC1E,CAAC,EAlagB,GAAG,KAAH,GAAG,GAAA,EAAA,CAAA,CAAA;;;;"}
1
+ {"version":3,"file":"object.mjs","sources":["../../src/object/object.mts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;AAOG;AACG,IAAW;AAAjB,CAAA,UAAiB,GAAG,EAAA;AAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCG;IACU,GAAA,CAAA,SAAS,GAAG,CACvB,CAAgB,EAChB,CAAgB,EAChB,EAAA,GAA0C,MAAM,CAAC,EAAE,KACxC;QACX,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAElC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;;AAGlC,QAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;AAAE,YAAA,OAAO,KAAK;QAErD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAChD,IAAA,CAAC;IAyDD,SAAgB,IAAI,CAIlB,GAAG,IAA8D,EAAA;AAIjE,QAAA,QAAQ,IAAI,CAAC,MAAM;YACjB,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI;AAE3B,gBAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAU,IAAI,CAAC;gBAEtC;;AAEE,gBAAA,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAClD;YAEd;YAEA,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;gBAEnB,OAAO,CAAC,MAAS,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;YAC1C;;IAEJ;AA5BgB,IAAA,GAAA,CAAA,IAAI,OA4BnB;IAyDD,SAAgB,IAAI,CAIlB,GAAG,IAEwC,EAAA;AAI3C,QAAA,QAAQ,IAAI,CAAC,MAAM;YACjB,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI;AAE3B,gBAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAU,IAAI,CAAC;gBAEtC;;AAEE,gBAAA,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACnD;YAEd;YAEA,KAAK,CAAC,EAAE;AACN,gBAAA,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;gBAEnB,OAAO,CAA2B,MAAU,KAAI;;oBAE9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAA6B,CAGxD;AAED,oBAAA,OAAO,MAAM;AACf,gBAAA,CAAC;YACH;;IAEJ;AAtCgB,IAAA,GAAA,CAAA,IAAI,OAsCnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CG;AACU,IAAA,GAAA,CAAA,WAAW,GAAG,CAGzB,OAAgB;;AAWhB,IAAA,MAAM,CAAC,WAAW,CAAC,OAAO,CAAU;AAEtC;;;;;;;;;;;;;;;;;AAiBG;AACU,IAAA,GAAA,CAAA,KAAK,GAAG,CACnB,GAAG,OAAgB;;IAGnB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAU;AAC1E,CAAC,EAlUgB,GAAG,KAAH,GAAG,GAAA,EAAA,CAAA,CAAA;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-data-forge",
3
- "version": "6.6.0",
3
+ "version": "6.7.0",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript",
@@ -305,102 +305,6 @@ export namespace Obj {
305
305
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
306
306
  Object.fromEntries(entries) as never;
307
307
 
308
- /**
309
- * @internal
310
- * Internal type utilities for the Obj module.
311
- */
312
- declare namespace TsDataForgeInternals {
313
- type RecursionLimit = 20;
314
-
315
- /** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */
316
- export type EntriesToObject<
317
- Entries extends readonly (readonly [PropertyKey, unknown])[],
318
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
319
- > = Readonly<EntriesToObjectImpl<{}, Entries>>;
320
-
321
- /** @internal */
322
- type EntriesToObjectImpl<
323
- R,
324
- Entries extends readonly (readonly [PropertyKey, unknown])[],
325
- > =
326
- TypeEq<Entries['length'], 0> extends true
327
- ? R
328
- : EntriesToObjectImpl<
329
- R & Readonly<Record<Entries[0][0], Entries[0][1]>>,
330
- List.Tail<Entries>
331
- >;
332
-
333
- /**
334
- * - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`
335
- * - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |
336
- * 'b' | 'c' | 'x' | 'y' | 'z'`
337
- *
338
- * @note To handle the second example above, recursion needs to be performed on infinite-length Entries,
339
- * but since the timing to stop cannot be determined, a recursion limit is set.
340
- */
341
- export type KeysOfEntries<
342
- Entries extends readonly (readonly [PropertyKey, unknown])[],
343
- > = KeysOfEntriesImpl<never, Entries, RecursionLimit>;
344
-
345
- type KeysOfEntriesImpl<
346
- K,
347
- Entries extends readonly (readonly [PropertyKey, unknown])[],
348
- RemainingNumRecursions extends number,
349
- > =
350
- TypeEq<RemainingNumRecursions, 0> extends true
351
- ? K
352
- : TypeEq<Entries['length'], 0> extends true
353
- ? K
354
- : KeysOfEntriesImpl<
355
- K | Entries[0][0],
356
- List.Tail<Entries>,
357
- Decrement<RemainingNumRecursions>
358
- >;
359
-
360
- export type ValuesOfEntries<
361
- Entries extends readonly (readonly [PropertyKey, unknown])[],
362
- > = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;
363
-
364
- type ValuesOfEntriesImpl<
365
- K,
366
- Entries extends readonly (readonly [PropertyKey, unknown])[],
367
- RemainingNumRecursions extends number,
368
- > =
369
- TypeEq<RemainingNumRecursions, 0> extends true
370
- ? K
371
- : TypeEq<Entries['length'], 0> extends true
372
- ? K
373
- : ValuesOfEntriesImpl<
374
- K | Entries[0][1],
375
- List.Tail<Entries>,
376
- Decrement<RemainingNumRecursions>
377
- >;
378
-
379
- export type PartialIfKeyIsUnion<K, T> =
380
- IsUnion<K> extends true ? Partial<T> : T;
381
-
382
- /** Merges two object types where keys in B override keys in A. */
383
- type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = Readonly<{
384
- [K in keyof A | keyof B]: K extends keyof B
385
- ? B[K]
386
- : K extends keyof A
387
- ? A[K]
388
- : never;
389
- }>;
390
-
391
- /** Sequentially merges a tuple of object types from left to right. */
392
- export type MergeAll<
393
- Records extends readonly UnknownRecord[],
394
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
395
- Acc extends UnknownRecord = {},
396
- > = Records extends readonly [
397
- infer First extends UnknownRecord,
398
- ...infer Rest extends readonly UnknownRecord[],
399
- ]
400
- ? MergeAll<Rest, MergeTwo<Acc, First>>
401
- : Acc;
402
- }
403
-
404
308
  /**
405
309
  * Merges multiple records into a single record using `Object.assign`.
406
310
  * Later records override properties from earlier records with the same key.
@@ -425,3 +329,174 @@ export namespace Obj {
425
329
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
426
330
  Object.fromEntries(records.flatMap((r) => Object.entries(r))) as never;
427
331
  }
332
+
333
+ /**
334
+ * @internal
335
+ * Internal type utilities for the Obj module.
336
+ */
337
+ declare namespace TsDataForgeInternals {
338
+ type RecursionLimit = 20;
339
+
340
+ /** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */
341
+ export type EntriesToObject<
342
+ Entries extends readonly (readonly [PropertyKey, unknown])[],
343
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
344
+ > = Readonly<EntriesToObjectImpl<{}, Entries>>;
345
+
346
+ /** @internal */
347
+ type EntriesToObjectImpl<
348
+ R,
349
+ Entries extends readonly (readonly [PropertyKey, unknown])[],
350
+ > =
351
+ TypeEq<Entries['length'], 0> extends true
352
+ ? R
353
+ : EntriesToObjectImpl<
354
+ R & Readonly<Record<Entries[0][0], Entries[0][1]>>,
355
+ List.Tail<Entries>
356
+ >;
357
+
358
+ /**
359
+ * - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`
360
+ * - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |
361
+ * 'b' | 'c' | 'x' | 'y' | 'z'`
362
+ *
363
+ * @note To handle the second example above, recursion needs to be performed on infinite-length Entries,
364
+ * but since the timing to stop cannot be determined, a recursion limit is set.
365
+ */
366
+ export type KeysOfEntries<
367
+ Entries extends readonly (readonly [PropertyKey, unknown])[],
368
+ > = KeysOfEntriesImpl<never, Entries, RecursionLimit>;
369
+
370
+ type KeysOfEntriesImpl<
371
+ K,
372
+ Entries extends readonly (readonly [PropertyKey, unknown])[],
373
+ RemainingNumRecursions extends number,
374
+ > =
375
+ TypeEq<RemainingNumRecursions, 0> extends true
376
+ ? K
377
+ : TypeEq<Entries['length'], 0> extends true
378
+ ? K
379
+ : KeysOfEntriesImpl<
380
+ K | Entries[0][0],
381
+ List.Tail<Entries>,
382
+ Decrement<RemainingNumRecursions>
383
+ >;
384
+
385
+ export type ValuesOfEntries<
386
+ Entries extends readonly (readonly [PropertyKey, unknown])[],
387
+ > = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;
388
+
389
+ type ValuesOfEntriesImpl<
390
+ K,
391
+ Entries extends readonly (readonly [PropertyKey, unknown])[],
392
+ RemainingNumRecursions extends number,
393
+ > =
394
+ TypeEq<RemainingNumRecursions, 0> extends true
395
+ ? K
396
+ : TypeEq<Entries['length'], 0> extends true
397
+ ? K
398
+ : ValuesOfEntriesImpl<
399
+ K | Entries[0][1],
400
+ List.Tail<Entries>,
401
+ Decrement<RemainingNumRecursions>
402
+ >;
403
+
404
+ export type PartialIfKeyIsUnion<K, T> =
405
+ IsUnion<K> extends true ? Partial<T> : T;
406
+
407
+ /**
408
+ * Merges two object types where keys in B override keys in A, preserving optional modifiers.
409
+ *
410
+ * This implementation uses a sophisticated technique to preserve optional property modifiers (`?`)
411
+ * during the merge operation, which would otherwise be lost in a naive mapped type implementation.
412
+ *
413
+ * ## Core Technique: Optional Property Detection
414
+ *
415
+ * Uses `{} extends Pick<T, K>` to determine if a property is optional:
416
+ * - **Required property**: `Pick<T, 'x'>` = `{ x: number }` → `{}` does NOT extend it (false)
417
+ * - **Optional property**: `Pick<T, 'y'>` = `{ y?: string }` → `{}` DOES extend it (true)
418
+ *
419
+ * This works because `{}` (empty object) is assignable to objects with only optional properties
420
+ * but not to objects with required properties.
421
+ *
422
+ * ## Implementation Strategy
423
+ *
424
+ * The type is constructed as an intersection of five mapped types:
425
+ *
426
+ * 1. **Required properties from B** - Properties in B that are required (override A completely)
427
+ * 2. **Optional properties from B (not in A)** - New optional properties from B
428
+ * 3. **Optional properties from B (in A)** - Union of A[K] | B[K] to preserve both possibilities
429
+ * 4. **Required properties only in A** - Properties in A but not in B that are required
430
+ * 5. **Optional properties only in A** - Properties in A but not in B that are optional (with `?` modifier)
431
+ *
432
+ * Finally, the intersection is flattened using an optional-preserving identity mapping that
433
+ * re-applies the optional detection logic to maintain the `?` modifiers in the final type.
434
+ *
435
+ * @example
436
+ * ```ts
437
+ * type A = { x: number; y?: string };
438
+ * type B = { y?: number; z?: boolean };
439
+ * type Result = MergeTwo<A, B>;
440
+ * // Result: { x: number; y?: string | number; z?: boolean }
441
+ * ```
442
+ */
443
+ // transformer-ignore-next-line
444
+ type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = {
445
+ // 1. Required properties from B (override A completely)
446
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
447
+ readonly [K in keyof B as {} extends Pick<B, K> ? never : K]: B[K];
448
+ } & {
449
+ // 2. Optional properties from B that are NOT in A
450
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
451
+ readonly [K in keyof B as {} extends Pick<B, K>
452
+ ? K extends keyof A
453
+ ? never
454
+ : K
455
+ : never]?: B[K];
456
+ } & {
457
+ // 3. Optional properties from B that ARE in A (create union)
458
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
459
+ readonly [K in keyof B as {} extends Pick<B, K>
460
+ ? K extends keyof A
461
+ ? K
462
+ : never
463
+ : never]?: K extends keyof A ? A[K] | B[K] : never;
464
+ } & {
465
+ // 4. Required properties only in A (not overridden by B)
466
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
467
+ readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K>
468
+ ? never
469
+ : K]: A[K];
470
+ } & {
471
+ // 5. Optional properties only in A (not overridden by B)
472
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
473
+ readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K>
474
+ ? K
475
+ : never]?: A[K];
476
+ } extends infer O
477
+ ? Readonly<
478
+ {
479
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
480
+ [K in keyof O as {} extends Pick<O, K> ? never : K]: O[K];
481
+ } & {
482
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
483
+ [K in keyof O as {} extends Pick<O, K> ? K : never]?: O[K];
484
+ }
485
+ >
486
+ : never;
487
+
488
+ /** Sequentially merges a tuple of object types from left to right. */
489
+ export type MergeAll<
490
+ Records extends readonly UnknownRecord[],
491
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
492
+ Acc extends UnknownRecord = {},
493
+ > =
494
+ IsFixedLengthList<Records> extends false
495
+ ? ArrayElement<Records>
496
+ : Records extends readonly [
497
+ infer First extends UnknownRecord,
498
+ ...infer Rest extends readonly UnknownRecord[],
499
+ ]
500
+ ? MergeAll<Rest, MergeTwo<Acc, First>>
501
+ : Acc;
502
+ }
@@ -238,4 +238,237 @@ describe('merge', () => {
238
238
 
239
239
  assert.deepStrictEqual(result, { key: 42 });
240
240
  });
241
+
242
+ test('type: MergeAll with four objects', () => {
243
+ const a = { a: 1, b: 2 } as const;
244
+
245
+ const b = { b: 3, c: 4 } as const;
246
+
247
+ const c = { c: 5, d: 6 } as const;
248
+
249
+ const d = { d: 7, e: 8 } as const;
250
+
251
+ const result = Obj.merge(a, b, c, d);
252
+
253
+ expectType<typeof result, Readonly<{ a: 1; b: 3; c: 5; d: 7; e: 8 }>>('=');
254
+
255
+ assert.deepStrictEqual(result, { a: 1, b: 3, c: 5, d: 7, e: 8 });
256
+ });
257
+
258
+ test('type: MergeAll with same key multiple times', () => {
259
+ const a = { x: 'first' } as const;
260
+
261
+ const b = { x: 'second' } as const;
262
+
263
+ const c = { x: 'third' } as const;
264
+
265
+ const result = Obj.merge(a, b, c);
266
+
267
+ expectType<typeof result, Readonly<{ x: 'third' }>>('=');
268
+
269
+ assert.deepStrictEqual(result, { x: 'third' });
270
+ });
271
+
272
+ test('type: MergeAll with disjoint keys', () => {
273
+ const a = { a: 1 } as const;
274
+
275
+ const b = { b: 2 } as const;
276
+
277
+ const c = { c: 3 } as const;
278
+
279
+ const result = Obj.merge(a, b, c);
280
+
281
+ expectType<typeof result, Readonly<{ a: 1; b: 2; c: 3 }>>('=');
282
+
283
+ assert.deepStrictEqual(result, { a: 1, b: 2, c: 3 });
284
+ });
285
+
286
+ test('type: MergeAll with complex nested types', () => {
287
+ const a = { value: { nested: 1 } } as const;
288
+
289
+ const b = { value: { nested: 2, extra: 'text' } } as const;
290
+
291
+ const result = Obj.merge(a, b);
292
+
293
+ expectType<
294
+ typeof result,
295
+ DeepReadonly<{ value: { nested: 2; extra: 'text' } }>
296
+ >('=');
297
+
298
+ assert.deepStrictEqual(result, { value: { nested: 2, extra: 'text' } });
299
+ });
300
+
301
+ test('type: MergeAll with mixed value types', () => {
302
+ const a = { x: 1, y: 'string' } as const;
303
+
304
+ const b = { y: 2, z: true } as const;
305
+
306
+ const c = { z: false, w: undefined } as const;
307
+
308
+ const result = Obj.merge(a, b, c);
309
+
310
+ expectType<typeof result, Readonly<{ x: 1; y: 2; z: false; w: undefined }>>(
311
+ '=',
312
+ );
313
+
314
+ assert.deepStrictEqual(result, { x: 1, y: 2, z: false, w: undefined });
315
+ });
316
+
317
+ test('type: MergeAll with mixed value types with optional properties', () => {
318
+ const a: Readonly<{ x: number; y?: string }> = {
319
+ x: 1,
320
+ y: 'string',
321
+ } as const;
322
+
323
+ const b: Readonly<{ y?: number; z?: boolean }> = { y: 2, z: true } as const;
324
+
325
+ const c: Readonly<{ z?: boolean; w?: undefined }> = {
326
+ z: false,
327
+ w: undefined,
328
+ } as const;
329
+
330
+ const result = Obj.merge(a, b, c);
331
+
332
+ expectType<
333
+ typeof result,
334
+ Readonly<{ x: number; y?: string | number; z?: boolean; w?: undefined }>
335
+ >('=');
336
+
337
+ assert.deepStrictEqual(result, { x: 1, y: 2, z: false, w: undefined });
338
+ });
339
+
340
+ test('type: MergeAll empty array produces empty object', () => {
341
+ const result = Obj.merge();
342
+
343
+ expectType<typeof result, {}>('=');
344
+
345
+ assert.deepStrictEqual(result, {});
346
+ });
347
+
348
+ test('type: MergeAll with arrays as values', () => {
349
+ const a = { items: [1, 2] } as const;
350
+
351
+ const b = { items: [3, 4, 5] } as const;
352
+
353
+ const result = Obj.merge(a, b);
354
+
355
+ expectType<typeof result, Readonly<{ items: readonly [3, 4, 5] }>>('=');
356
+
357
+ assert.deepStrictEqual(result, { items: [3, 4, 5] });
358
+ });
359
+
360
+ test('type: MergeAll preserves literal types', () => {
361
+ const a = { status: 'pending', count: 0 } as const;
362
+
363
+ const b = { status: 'completed' } as const;
364
+
365
+ const result = Obj.merge(a, b);
366
+
367
+ expectType<typeof result, Readonly<{ status: 'completed'; count: 0 }>>('=');
368
+
369
+ assert.deepStrictEqual(result, { status: 'completed', count: 0 });
370
+ });
371
+
372
+ test('type: MergeAll with UnknownRecord[] produces UnknownRecord', () => {
373
+ const records: readonly UnknownRecord[] = [
374
+ { a: 1, b: 2 },
375
+ { b: 3, c: 4 },
376
+ { c: 5, d: 6 },
377
+ ] as const;
378
+
379
+ const result = Obj.merge(...records);
380
+
381
+ expectType<typeof result, UnknownRecord>('=');
382
+
383
+ assert.deepStrictEqual(result, { a: 1, b: 3, c: 5, d: 6 });
384
+ });
385
+
386
+ test('type: MergeAll with specific typed array', () => {
387
+ type MyRecord = Readonly<{ x: number; y: string }>;
388
+
389
+ const records: readonly MyRecord[] = [
390
+ { x: 1, y: 'a' },
391
+ { x: 2, y: 'b' },
392
+ { x: 3, y: 'c' },
393
+ ] as const;
394
+
395
+ const result = Obj.merge(...records);
396
+
397
+ expectType<typeof result, MyRecord>('=');
398
+
399
+ assert.deepStrictEqual(result, { x: 3, y: 'c' });
400
+ });
401
+
402
+ test('type: MergeAll with fixed length typed array', () => {
403
+ type MyRecord = Readonly<{ x: number; y: string }>;
404
+
405
+ const records: ArrayOfLength<3, MyRecord> = [
406
+ { x: 1, y: 'a' },
407
+ { x: 2, y: 'b' },
408
+ { x: 3, y: 'c' },
409
+ ] as const;
410
+
411
+ const result = Obj.merge(...records);
412
+
413
+ expectType<typeof result, MyRecord>('=');
414
+
415
+ assert.deepStrictEqual(result, { x: 3, y: 'c' });
416
+ });
417
+
418
+ test('type: MergeAll with array and optional properties', () => {
419
+ type RecordWithOptional = Readonly<{ x: number; y?: string }>;
420
+
421
+ const records: readonly RecordWithOptional[] = [
422
+ { x: 1, y: 'a' },
423
+ { x: 2 },
424
+ ] as const;
425
+
426
+ const result = Obj.merge(...records);
427
+
428
+ expectType<typeof result, RecordWithOptional>('=');
429
+
430
+ assert.deepStrictEqual(result, { x: 2, y: 'a' });
431
+ });
432
+
433
+ test('type: MergeAll with fixed length typed array and optional properties', () => {
434
+ type RecordWithOptional = Readonly<{ x: number; y?: string }>;
435
+
436
+ const records: ArrayOfLength<2, RecordWithOptional> = [
437
+ { x: 1, y: 'a' },
438
+ { x: 2 },
439
+ ] as const;
440
+
441
+ const result = Obj.merge(...records);
442
+
443
+ expectType<typeof result, RecordWithOptional>('=');
444
+
445
+ assert.deepStrictEqual(result, { x: 2, y: 'a' });
446
+ });
447
+
448
+ test('type: MergeAll with empty dynamic array', () => {
449
+ const records: readonly UnknownRecord[] = [] as const;
450
+
451
+ const result = Obj.merge(...records);
452
+
453
+ expectType<typeof result, UnknownRecord>('=');
454
+
455
+ assert.deepStrictEqual(result, {});
456
+ });
457
+
458
+ test('type: MergeAll with union type array', () => {
459
+ type RecordA = Readonly<{ a: number; b: string }>;
460
+
461
+ type RecordB = Readonly<{ c: boolean; d: number }>;
462
+
463
+ const records: readonly (RecordA | RecordB)[] = [
464
+ { a: 1, b: 'text' },
465
+ { c: true, d: 42 },
466
+ ] as const;
467
+
468
+ const result = Obj.merge(...records);
469
+
470
+ expectType<typeof result, RecordA | RecordB>('=');
471
+
472
+ assert.deepStrictEqual(result, { a: 1, b: 'text', c: true, d: 42 });
473
+ });
241
474
  });