ts-data-forge 6.6.0 → 6.8.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.
- package/dist/array/impl/array-utils-transformation.d.mts +25 -0
- package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-transformation.mjs +36 -1
- package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
- package/dist/array/impl/index.mjs +1 -1
- package/dist/object/object.d.mts +92 -41
- package/dist/object/object.d.mts.map +1 -1
- package/dist/object/object.mjs +4 -0
- package/dist/object/object.mjs.map +1 -1
- package/package.json +5 -5
- package/src/array/impl/array-utils-transformation.mts +40 -0
- package/src/array/impl/array-utils-transformation.test.mts +54 -0
- package/src/object/object.mts +175 -96
- package/src/object/object.test.mts +233 -0
|
@@ -379,4 +379,29 @@ export declare const zip: <const Ar1 extends readonly unknown[], const Ar2 exten
|
|
|
379
379
|
* @see {@link partition}
|
|
380
380
|
*/
|
|
381
381
|
export declare const chunk: typeof partition;
|
|
382
|
+
/**
|
|
383
|
+
* Computes the cartesian product of arrays.
|
|
384
|
+
* cartesianProduct([[1,2], [3,4]]) => [[1,3], [1,4], [2,3], [2,4]]
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
*
|
|
388
|
+
*
|
|
389
|
+
* ```ts
|
|
390
|
+
* const sizes = ['S', 'M'] as const;
|
|
391
|
+
*
|
|
392
|
+
* const colors = ['red', 'blue'] as const;
|
|
393
|
+
*
|
|
394
|
+
* const combinations = Arr.cartesianProduct([sizes, colors]);
|
|
395
|
+
*
|
|
396
|
+
* const expectedCombinations = [
|
|
397
|
+
* ['S', 'red'],
|
|
398
|
+
* ['S', 'blue'],
|
|
399
|
+
* ['M', 'red'],
|
|
400
|
+
* ['M', 'blue'],
|
|
401
|
+
* ] as const;
|
|
402
|
+
*
|
|
403
|
+
* assert.deepStrictEqual(combinations, expectedCombinations);
|
|
404
|
+
* ```
|
|
405
|
+
*/
|
|
406
|
+
export declare const cartesianProduct: <T>(arrays: readonly (readonly T[])[]) => readonly (readonly T[])[];
|
|
382
407
|
//# sourceMappingURL=array-utils-transformation.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array-utils-transformation.d.mts","sourceRoot":"","sources":["../../../src/array/impl/array-utils-transformation.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"array-utils-transformation.d.mts","sourceRoot":"","sources":["../../../src/array/impl/array-utils-transformation.mts"],"names":[],"mappings":"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"}
|
|
@@ -37,6 +37,7 @@ import '../../number/num.mjs';
|
|
|
37
37
|
import '../../number/refined-number-utils.mjs';
|
|
38
38
|
import { seq, newArray } from './array-utils-creation.mjs';
|
|
39
39
|
import { size } from './array-utils-size.mjs';
|
|
40
|
+
import { isNonEmpty } from './array-utils-validation.mjs';
|
|
40
41
|
|
|
41
42
|
function map(...args) {
|
|
42
43
|
switch (args.length) {
|
|
@@ -331,6 +332,40 @@ tp(array1[i], array2[i]));
|
|
|
331
332
|
* @see {@link partition}
|
|
332
333
|
*/
|
|
333
334
|
const chunk = partition;
|
|
335
|
+
/**
|
|
336
|
+
* Computes the cartesian product of arrays.
|
|
337
|
+
* cartesianProduct([[1,2], [3,4]]) => [[1,3], [1,4], [2,3], [2,4]]
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
*
|
|
341
|
+
*
|
|
342
|
+
* ```ts
|
|
343
|
+
* const sizes = ['S', 'M'] as const;
|
|
344
|
+
*
|
|
345
|
+
* const colors = ['red', 'blue'] as const;
|
|
346
|
+
*
|
|
347
|
+
* const combinations = Arr.cartesianProduct([sizes, colors]);
|
|
348
|
+
*
|
|
349
|
+
* const expectedCombinations = [
|
|
350
|
+
* ['S', 'red'],
|
|
351
|
+
* ['S', 'blue'],
|
|
352
|
+
* ['M', 'red'],
|
|
353
|
+
* ['M', 'blue'],
|
|
354
|
+
* ] as const;
|
|
355
|
+
*
|
|
356
|
+
* assert.deepStrictEqual(combinations, expectedCombinations);
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
const cartesianProduct = (arrays) => {
|
|
360
|
+
if (!isNonEmpty(arrays))
|
|
361
|
+
return [[]];
|
|
362
|
+
const [first, ...rest] = arrays;
|
|
363
|
+
// If first array is empty, the result is empty
|
|
364
|
+
if (!isNonEmpty(first))
|
|
365
|
+
return [];
|
|
366
|
+
const restProduct = cartesianProduct(rest);
|
|
367
|
+
return first.flatMap((item) => restProduct.map((prod) => [item, ...prod]));
|
|
368
|
+
};
|
|
334
369
|
|
|
335
|
-
export { chunk, concat, filter, filterNot, flat, flatMap, groupBy, map, partition, scan, toReversed, toSorted, toSortedBy, uniq, uniqBy, zip };
|
|
370
|
+
export { cartesianProduct, chunk, concat, filter, filterNot, flat, flatMap, groupBy, map, partition, scan, toReversed, toSorted, toSortedBy, uniq, uniqBy, zip };
|
|
336
371
|
//# sourceMappingURL=array-utils-transformation.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array-utils-transformation.mjs","sources":["../../../src/array/impl/array-utils-transformation.mts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"array-utils-transformation.mjs","sources":["../../../src/array/impl/array-utils-transformation.mts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,6 @@ export { eq, equal, isSubset, isSuperset, setDifference, setIntersection, sorted
|
|
|
8
8
|
export { length, size } from './array-utils-size.mjs';
|
|
9
9
|
export { sliceClamped } from './array-utils-slice-clamped.mjs';
|
|
10
10
|
export { butLast, drop, rest, skip, skipLast, tail, take, takeLast } from './array-utils-slicing.mjs';
|
|
11
|
-
export { chunk, concat, filter, filterNot, flat, flatMap, groupBy, map, partition, scan, toReversed, toSorted, toSortedBy, uniq, uniqBy, zip } from './array-utils-transformation.mjs';
|
|
11
|
+
export { cartesianProduct, chunk, concat, filter, filterNot, flat, flatMap, groupBy, map, partition, scan, toReversed, toSorted, toSortedBy, uniq, uniqBy, zip } from './array-utils-transformation.mjs';
|
|
12
12
|
export { every, indexIsInRange, isArray, isArrayAtLeastLength, isArrayOfLength, isEmpty, isNonEmpty, some } from './array-utils-validation.mjs';
|
|
13
13
|
//# sourceMappingURL=index.mjs.map
|
package/dist/object/object.d.mts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
97
|
-
|
|
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
|
-
|
|
144
|
-
|
|
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,46 +187,15 @@ 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
|
-
|
|
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.
|
|
227
194
|
*
|
|
228
195
|
* @example
|
|
229
196
|
*
|
|
197
|
+
* <!-- doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->
|
|
198
|
+
*
|
|
230
199
|
* ```ts
|
|
231
200
|
* const a = { a: 0, b: 0 } as const;
|
|
232
201
|
* const b = { b: 1, c: 0 } as const;
|
|
@@ -236,10 +205,92 @@ export declare namespace Obj {
|
|
|
236
205
|
* assert.deepStrictEqual(result, { a: 0, b: 1, c: 0 });
|
|
237
206
|
* ```
|
|
238
207
|
*
|
|
208
|
+
* <!-- /doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->
|
|
209
|
+
*
|
|
239
210
|
* @param records - The records to merge
|
|
240
211
|
* @returns A new record with all properties merged
|
|
241
212
|
*/
|
|
242
|
-
|
|
243
|
-
|
|
213
|
+
const merge: <const Records extends readonly UnknownRecord[]>(...records: Records) => TsDataForgeInternals.MergeAll<Records>;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* @internal
|
|
217
|
+
* Internal type utilities for the Obj module.
|
|
218
|
+
*/
|
|
219
|
+
declare namespace TsDataForgeInternals {
|
|
220
|
+
type RecursionLimit = 20;
|
|
221
|
+
/** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */
|
|
222
|
+
type EntriesToObject<Entries extends readonly (readonly [PropertyKey, unknown])[]> = Readonly<EntriesToObjectImpl<{}, Entries>>;
|
|
223
|
+
/** @internal */
|
|
224
|
+
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>>;
|
|
225
|
+
/**
|
|
226
|
+
* - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`
|
|
227
|
+
* - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |
|
|
228
|
+
* 'b' | 'c' | 'x' | 'y' | 'z'`
|
|
229
|
+
*
|
|
230
|
+
* @note To handle the second example above, recursion needs to be performed on infinite-length Entries,
|
|
231
|
+
* but since the timing to stop cannot be determined, a recursion limit is set.
|
|
232
|
+
*/
|
|
233
|
+
type KeysOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = KeysOfEntriesImpl<never, Entries, RecursionLimit>;
|
|
234
|
+
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>>;
|
|
235
|
+
type ValuesOfEntries<Entries extends readonly (readonly [PropertyKey, unknown])[]> = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;
|
|
236
|
+
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>>;
|
|
237
|
+
type PartialIfKeyIsUnion<K, T> = IsUnion<K> extends true ? Partial<T> : T;
|
|
238
|
+
/**
|
|
239
|
+
* Merges two object types where keys in B override keys in A, preserving optional modifiers.
|
|
240
|
+
*
|
|
241
|
+
* This implementation uses a sophisticated technique to preserve optional property modifiers (`?`)
|
|
242
|
+
* during the merge operation, which would otherwise be lost in a naive mapped type implementation.
|
|
243
|
+
*
|
|
244
|
+
* ## Core Technique: Optional Property Detection
|
|
245
|
+
*
|
|
246
|
+
* Uses `{} extends Pick<T, K>` to determine if a property is optional:
|
|
247
|
+
* - **Required property**: `Pick<T, 'x'>` = `{ x: number }` → `{}` does NOT extend it (false)
|
|
248
|
+
* - **Optional property**: `Pick<T, 'y'>` = `{ y?: string }` → `{}` DOES extend it (true)
|
|
249
|
+
*
|
|
250
|
+
* This works because `{}` (empty object) is assignable to objects with only optional properties
|
|
251
|
+
* but not to objects with required properties.
|
|
252
|
+
*
|
|
253
|
+
* ## Implementation Strategy
|
|
254
|
+
*
|
|
255
|
+
* The type is constructed as an intersection of five mapped types:
|
|
256
|
+
*
|
|
257
|
+
* 1. **Required properties from B** - Properties in B that are required (override A completely)
|
|
258
|
+
* 2. **Optional properties from B (not in A)** - New optional properties from B
|
|
259
|
+
* 3. **Optional properties from B (in A)** - Union of A[K] | B[K] to preserve both possibilities
|
|
260
|
+
* 4. **Required properties only in A** - Properties in A but not in B that are required
|
|
261
|
+
* 5. **Optional properties only in A** - Properties in A but not in B that are optional (with `?` modifier)
|
|
262
|
+
*
|
|
263
|
+
* Finally, the intersection is flattened using an optional-preserving identity mapping that
|
|
264
|
+
* re-applies the optional detection logic to maintain the `?` modifiers in the final type.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* type A = { x: number; y?: string };
|
|
269
|
+
* type B = { y?: number; z?: boolean };
|
|
270
|
+
* type Result = MergeTwo<A, B>;
|
|
271
|
+
* // Result: { x: number; y?: string | number; z?: boolean }
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = {
|
|
275
|
+
readonly [K in keyof B as {} extends Pick<B, K> ? never : K]: B[K];
|
|
276
|
+
} & {
|
|
277
|
+
readonly [K in keyof B as {} extends Pick<B, K> ? K extends keyof A ? never : K : never]?: B[K];
|
|
278
|
+
} & {
|
|
279
|
+
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;
|
|
280
|
+
} & {
|
|
281
|
+
readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? never : K]: A[K];
|
|
282
|
+
} & {
|
|
283
|
+
readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? K : never]?: A[K];
|
|
284
|
+
} extends infer O ? Readonly<{
|
|
285
|
+
[K in keyof O as {} extends Pick<O, K> ? never : K]: O[K];
|
|
286
|
+
} & {
|
|
287
|
+
[K in keyof O as {} extends Pick<O, K> ? K : never]?: O[K];
|
|
288
|
+
}> : never;
|
|
289
|
+
/** Sequentially merges a tuple of object types from left to right. */
|
|
290
|
+
type MergeAll<Records extends readonly UnknownRecord[], Acc extends UnknownRecord = {}> = IsFixedLengthList<Records> extends false ? ArrayElement<Records> : Records extends readonly [
|
|
291
|
+
infer First extends UnknownRecord,
|
|
292
|
+
...infer Rest extends readonly UnknownRecord[]
|
|
293
|
+
] ? MergeAll<Rest, MergeTwo<Acc, First>> : Acc;
|
|
244
294
|
}
|
|
295
|
+
export {};
|
|
245
296
|
//# 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;
|
|
1
|
+
{"version":3,"file":"object.d.mts","sourceRoot":"","sources":["../../src/object/object.mts"],"names":[],"mappings":"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"}
|
package/dist/object/object.mjs
CHANGED
|
@@ -148,6 +148,8 @@ var Obj;
|
|
|
148
148
|
*
|
|
149
149
|
* @example
|
|
150
150
|
*
|
|
151
|
+
* <!-- doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->
|
|
152
|
+
*
|
|
151
153
|
* ```ts
|
|
152
154
|
* const a = { a: 0, b: 0 } as const;
|
|
153
155
|
* const b = { b: 1, c: 0 } as const;
|
|
@@ -157,6 +159,8 @@ var Obj;
|
|
|
157
159
|
* assert.deepStrictEqual(result, { a: 0, b: 1, c: 0 });
|
|
158
160
|
* ```
|
|
159
161
|
*
|
|
162
|
+
* <!-- /doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->
|
|
163
|
+
*
|
|
160
164
|
* @param records - The records to merge
|
|
161
165
|
* @returns A new record with all properties merged
|
|
162
166
|
*/
|
|
@@ -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;
|
|
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;;;;;;;;;;;;;;;;;;;;;AAqBG;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,EAtUgB,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.
|
|
3
|
+
"version": "6.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"@semantic-release/github": "12.0.6",
|
|
100
100
|
"@semantic-release/npm": "13.1.5",
|
|
101
101
|
"@semantic-release/release-notes-generator": "14.1.0",
|
|
102
|
-
"@types/node": "25.
|
|
102
|
+
"@types/node": "25.5.0",
|
|
103
103
|
"@types/react": "19.2.14",
|
|
104
104
|
"@vitest/browser-playwright": "4.0.18",
|
|
105
105
|
"@vitest/coverage-v8": "4.0.18",
|
|
@@ -107,9 +107,9 @@
|
|
|
107
107
|
"conventional-changelog-conventionalcommits": "9.3.0",
|
|
108
108
|
"cspell": "9.7.0",
|
|
109
109
|
"dedent": "^1.7.2",
|
|
110
|
-
"eslint": "9.39.
|
|
111
|
-
"eslint-config-typed": "4.7.
|
|
112
|
-
"github-settings-as-code": "1.2.
|
|
110
|
+
"eslint": "9.39.4",
|
|
111
|
+
"eslint-config-typed": "4.7.5",
|
|
112
|
+
"github-settings-as-code": "1.2.1",
|
|
113
113
|
"immer": "11.1.4",
|
|
114
114
|
"jiti": "2.6.1",
|
|
115
115
|
"markdownlint": "0.40.0",
|
|
@@ -4,6 +4,7 @@ import { asPositiveUint32, asUint32, Uint32 } from '../../number/index.mjs';
|
|
|
4
4
|
import { castMutable, tp } from '../../others/index.mjs';
|
|
5
5
|
import { newArray, seq } from './array-utils-creation.mjs';
|
|
6
6
|
import { size } from './array-utils-size.mjs';
|
|
7
|
+
import { isNonEmpty } from './array-utils-validation.mjs';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Creates a new array by transforming each element with a mapping function.
|
|
@@ -809,3 +810,42 @@ export const zip = <
|
|
|
809
810
|
* @see {@link partition}
|
|
810
811
|
*/
|
|
811
812
|
export const chunk = partition;
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Computes the cartesian product of arrays.
|
|
816
|
+
* cartesianProduct([[1,2], [3,4]]) => [[1,3], [1,4], [2,3], [2,4]]
|
|
817
|
+
*
|
|
818
|
+
* @example
|
|
819
|
+
*
|
|
820
|
+
*
|
|
821
|
+
* ```ts
|
|
822
|
+
* const sizes = ['S', 'M'] as const;
|
|
823
|
+
*
|
|
824
|
+
* const colors = ['red', 'blue'] as const;
|
|
825
|
+
*
|
|
826
|
+
* const combinations = Arr.cartesianProduct([sizes, colors]);
|
|
827
|
+
*
|
|
828
|
+
* const expectedCombinations = [
|
|
829
|
+
* ['S', 'red'],
|
|
830
|
+
* ['S', 'blue'],
|
|
831
|
+
* ['M', 'red'],
|
|
832
|
+
* ['M', 'blue'],
|
|
833
|
+
* ] as const;
|
|
834
|
+
*
|
|
835
|
+
* assert.deepStrictEqual(combinations, expectedCombinations);
|
|
836
|
+
* ```
|
|
837
|
+
*/
|
|
838
|
+
export const cartesianProduct = <T,>(
|
|
839
|
+
arrays: readonly (readonly T[])[],
|
|
840
|
+
): readonly (readonly T[])[] => {
|
|
841
|
+
if (!isNonEmpty(arrays)) return [[]];
|
|
842
|
+
|
|
843
|
+
const [first, ...rest] = arrays;
|
|
844
|
+
|
|
845
|
+
// If first array is empty, the result is empty
|
|
846
|
+
if (!isNonEmpty(first)) return [];
|
|
847
|
+
|
|
848
|
+
const restProduct = cartesianProduct(rest);
|
|
849
|
+
|
|
850
|
+
return first.flatMap((item) => restProduct.map((prod) => [item, ...prod]));
|
|
851
|
+
};
|
|
@@ -3,6 +3,7 @@ import { expectType } from '../../expect-type.mjs';
|
|
|
3
3
|
import { Optional } from '../../functional/index.mjs';
|
|
4
4
|
import { SafeUint } from '../../number/index.mjs';
|
|
5
5
|
import {
|
|
6
|
+
cartesianProduct,
|
|
6
7
|
concat,
|
|
7
8
|
filter,
|
|
8
9
|
filterNot,
|
|
@@ -1093,4 +1094,57 @@ describe('Arr transformations', () => {
|
|
|
1093
1094
|
assert.deepStrictEqual(result, []);
|
|
1094
1095
|
});
|
|
1095
1096
|
});
|
|
1097
|
+
|
|
1098
|
+
describe(cartesianProduct, () => {
|
|
1099
|
+
test('Empty array', () => {
|
|
1100
|
+
assert.deepStrictEqual(cartesianProduct([]), [[]]);
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
test('Single array', () => {
|
|
1104
|
+
assert.deepStrictEqual(cartesianProduct([[1, 2, 3]]), [[1], [2], [3]]);
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
test('Two arrays', () => {
|
|
1108
|
+
assert.deepStrictEqual(
|
|
1109
|
+
cartesianProduct([
|
|
1110
|
+
[1, 2],
|
|
1111
|
+
[3, 4],
|
|
1112
|
+
]),
|
|
1113
|
+
[
|
|
1114
|
+
[1, 3],
|
|
1115
|
+
[1, 4],
|
|
1116
|
+
[2, 3],
|
|
1117
|
+
[2, 4],
|
|
1118
|
+
],
|
|
1119
|
+
);
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
test('Three arrays', () => {
|
|
1123
|
+
assert.deepStrictEqual(
|
|
1124
|
+
cartesianProduct<string | number | boolean>([
|
|
1125
|
+
['a', 'b'],
|
|
1126
|
+
[1, 2],
|
|
1127
|
+
[true, false],
|
|
1128
|
+
]),
|
|
1129
|
+
[
|
|
1130
|
+
['a', 1, true],
|
|
1131
|
+
['a', 1, false],
|
|
1132
|
+
['a', 2, true],
|
|
1133
|
+
['a', 2, false],
|
|
1134
|
+
['b', 1, true],
|
|
1135
|
+
['b', 1, false],
|
|
1136
|
+
['b', 2, true],
|
|
1137
|
+
['b', 2, false],
|
|
1138
|
+
],
|
|
1139
|
+
);
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
test('Array with empty array', () => {
|
|
1143
|
+
assert.deepStrictEqual(cartesianProduct([[1, 2], [], [3, 4]]), []);
|
|
1144
|
+
});
|
|
1145
|
+
|
|
1146
|
+
test('Single element arrays', () => {
|
|
1147
|
+
assert.deepStrictEqual(cartesianProduct([[1], [2], [3]]), [[1, 2, 3]]);
|
|
1148
|
+
});
|
|
1149
|
+
});
|
|
1096
1150
|
});
|
package/src/object/object.mts
CHANGED
|
@@ -305,108 +305,14 @@ 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.
|
|
407
311
|
*
|
|
408
312
|
* @example
|
|
409
313
|
*
|
|
314
|
+
* <!-- doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->
|
|
315
|
+
*
|
|
410
316
|
* ```ts
|
|
411
317
|
* const a = { a: 0, b: 0 } as const;
|
|
412
318
|
* const b = { b: 1, c: 0 } as const;
|
|
@@ -416,6 +322,8 @@ export namespace Obj {
|
|
|
416
322
|
* assert.deepStrictEqual(result, { a: 0, b: 1, c: 0 });
|
|
417
323
|
* ```
|
|
418
324
|
*
|
|
325
|
+
* <!-- /doc:embed:jsdoc:example:./samples/src/object/merge-example.mts -->
|
|
326
|
+
*
|
|
419
327
|
* @param records - The records to merge
|
|
420
328
|
* @returns A new record with all properties merged
|
|
421
329
|
*/
|
|
@@ -425,3 +333,174 @@ export namespace Obj {
|
|
|
425
333
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
426
334
|
Object.fromEntries(records.flatMap((r) => Object.entries(r))) as never;
|
|
427
335
|
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @internal
|
|
339
|
+
* Internal type utilities for the Obj module.
|
|
340
|
+
*/
|
|
341
|
+
declare namespace TsDataForgeInternals {
|
|
342
|
+
type RecursionLimit = 20;
|
|
343
|
+
|
|
344
|
+
/** - `[['x', 1], ['y', 3]]` -> `{ x: 1, y: 3 }` */
|
|
345
|
+
export type EntriesToObject<
|
|
346
|
+
Entries extends readonly (readonly [PropertyKey, unknown])[],
|
|
347
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
348
|
+
> = Readonly<EntriesToObjectImpl<{}, Entries>>;
|
|
349
|
+
|
|
350
|
+
/** @internal */
|
|
351
|
+
type EntriesToObjectImpl<
|
|
352
|
+
R,
|
|
353
|
+
Entries extends readonly (readonly [PropertyKey, unknown])[],
|
|
354
|
+
> =
|
|
355
|
+
TypeEq<Entries['length'], 0> extends true
|
|
356
|
+
? R
|
|
357
|
+
: EntriesToObjectImpl<
|
|
358
|
+
R & Readonly<Record<Entries[0][0], Entries[0][1]>>,
|
|
359
|
+
List.Tail<Entries>
|
|
360
|
+
>;
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* - `['x' | 'y' | 'z', number][]]` -> `'x' | 'y' | 'z'`
|
|
364
|
+
* - `[['a' | 'b' | 'c', number], ...['x' | 'y' | 'z', number][]]` -> `'a' |
|
|
365
|
+
* 'b' | 'c' | 'x' | 'y' | 'z'`
|
|
366
|
+
*
|
|
367
|
+
* @note To handle the second example above, recursion needs to be performed on infinite-length Entries,
|
|
368
|
+
* but since the timing to stop cannot be determined, a recursion limit is set.
|
|
369
|
+
*/
|
|
370
|
+
export type KeysOfEntries<
|
|
371
|
+
Entries extends readonly (readonly [PropertyKey, unknown])[],
|
|
372
|
+
> = KeysOfEntriesImpl<never, Entries, RecursionLimit>;
|
|
373
|
+
|
|
374
|
+
type KeysOfEntriesImpl<
|
|
375
|
+
K,
|
|
376
|
+
Entries extends readonly (readonly [PropertyKey, unknown])[],
|
|
377
|
+
RemainingNumRecursions extends number,
|
|
378
|
+
> =
|
|
379
|
+
TypeEq<RemainingNumRecursions, 0> extends true
|
|
380
|
+
? K
|
|
381
|
+
: TypeEq<Entries['length'], 0> extends true
|
|
382
|
+
? K
|
|
383
|
+
: KeysOfEntriesImpl<
|
|
384
|
+
K | Entries[0][0],
|
|
385
|
+
List.Tail<Entries>,
|
|
386
|
+
Decrement<RemainingNumRecursions>
|
|
387
|
+
>;
|
|
388
|
+
|
|
389
|
+
export type ValuesOfEntries<
|
|
390
|
+
Entries extends readonly (readonly [PropertyKey, unknown])[],
|
|
391
|
+
> = ValuesOfEntriesImpl<never, Entries, RecursionLimit>;
|
|
392
|
+
|
|
393
|
+
type ValuesOfEntriesImpl<
|
|
394
|
+
K,
|
|
395
|
+
Entries extends readonly (readonly [PropertyKey, unknown])[],
|
|
396
|
+
RemainingNumRecursions extends number,
|
|
397
|
+
> =
|
|
398
|
+
TypeEq<RemainingNumRecursions, 0> extends true
|
|
399
|
+
? K
|
|
400
|
+
: TypeEq<Entries['length'], 0> extends true
|
|
401
|
+
? K
|
|
402
|
+
: ValuesOfEntriesImpl<
|
|
403
|
+
K | Entries[0][1],
|
|
404
|
+
List.Tail<Entries>,
|
|
405
|
+
Decrement<RemainingNumRecursions>
|
|
406
|
+
>;
|
|
407
|
+
|
|
408
|
+
export type PartialIfKeyIsUnion<K, T> =
|
|
409
|
+
IsUnion<K> extends true ? Partial<T> : T;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Merges two object types where keys in B override keys in A, preserving optional modifiers.
|
|
413
|
+
*
|
|
414
|
+
* This implementation uses a sophisticated technique to preserve optional property modifiers (`?`)
|
|
415
|
+
* during the merge operation, which would otherwise be lost in a naive mapped type implementation.
|
|
416
|
+
*
|
|
417
|
+
* ## Core Technique: Optional Property Detection
|
|
418
|
+
*
|
|
419
|
+
* Uses `{} extends Pick<T, K>` to determine if a property is optional:
|
|
420
|
+
* - **Required property**: `Pick<T, 'x'>` = `{ x: number }` → `{}` does NOT extend it (false)
|
|
421
|
+
* - **Optional property**: `Pick<T, 'y'>` = `{ y?: string }` → `{}` DOES extend it (true)
|
|
422
|
+
*
|
|
423
|
+
* This works because `{}` (empty object) is assignable to objects with only optional properties
|
|
424
|
+
* but not to objects with required properties.
|
|
425
|
+
*
|
|
426
|
+
* ## Implementation Strategy
|
|
427
|
+
*
|
|
428
|
+
* The type is constructed as an intersection of five mapped types:
|
|
429
|
+
*
|
|
430
|
+
* 1. **Required properties from B** - Properties in B that are required (override A completely)
|
|
431
|
+
* 2. **Optional properties from B (not in A)** - New optional properties from B
|
|
432
|
+
* 3. **Optional properties from B (in A)** - Union of A[K] | B[K] to preserve both possibilities
|
|
433
|
+
* 4. **Required properties only in A** - Properties in A but not in B that are required
|
|
434
|
+
* 5. **Optional properties only in A** - Properties in A but not in B that are optional (with `?` modifier)
|
|
435
|
+
*
|
|
436
|
+
* Finally, the intersection is flattened using an optional-preserving identity mapping that
|
|
437
|
+
* re-applies the optional detection logic to maintain the `?` modifiers in the final type.
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```ts
|
|
441
|
+
* type A = { x: number; y?: string };
|
|
442
|
+
* type B = { y?: number; z?: boolean };
|
|
443
|
+
* type Result = MergeTwo<A, B>;
|
|
444
|
+
* // Result: { x: number; y?: string | number; z?: boolean }
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
// transformer-ignore-next-line
|
|
448
|
+
type MergeTwo<A extends UnknownRecord, B extends UnknownRecord> = {
|
|
449
|
+
// 1. Required properties from B (override A completely)
|
|
450
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
451
|
+
readonly [K in keyof B as {} extends Pick<B, K> ? never : K]: B[K];
|
|
452
|
+
} & {
|
|
453
|
+
// 2. Optional properties from B that are NOT in A
|
|
454
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
455
|
+
readonly [K in keyof B as {} extends Pick<B, K>
|
|
456
|
+
? K extends keyof A
|
|
457
|
+
? never
|
|
458
|
+
: K
|
|
459
|
+
: never]?: B[K];
|
|
460
|
+
} & {
|
|
461
|
+
// 3. Optional properties from B that ARE in A (create union)
|
|
462
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
463
|
+
readonly [K in keyof B as {} extends Pick<B, K>
|
|
464
|
+
? K extends keyof A
|
|
465
|
+
? K
|
|
466
|
+
: never
|
|
467
|
+
: never]?: K extends keyof A ? A[K] | B[K] : never;
|
|
468
|
+
} & {
|
|
469
|
+
// 4. Required properties only in A (not overridden by B)
|
|
470
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
471
|
+
readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K>
|
|
472
|
+
? never
|
|
473
|
+
: K]: A[K];
|
|
474
|
+
} & {
|
|
475
|
+
// 5. Optional properties only in A (not overridden by B)
|
|
476
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
477
|
+
readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K>
|
|
478
|
+
? K
|
|
479
|
+
: never]?: A[K];
|
|
480
|
+
} extends infer O
|
|
481
|
+
? Readonly<
|
|
482
|
+
{
|
|
483
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
484
|
+
[K in keyof O as {} extends Pick<O, K> ? never : K]: O[K];
|
|
485
|
+
} & {
|
|
486
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
487
|
+
[K in keyof O as {} extends Pick<O, K> ? K : never]?: O[K];
|
|
488
|
+
}
|
|
489
|
+
>
|
|
490
|
+
: never;
|
|
491
|
+
|
|
492
|
+
/** Sequentially merges a tuple of object types from left to right. */
|
|
493
|
+
export type MergeAll<
|
|
494
|
+
Records extends readonly UnknownRecord[],
|
|
495
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
496
|
+
Acc extends UnknownRecord = {},
|
|
497
|
+
> =
|
|
498
|
+
IsFixedLengthList<Records> extends false
|
|
499
|
+
? ArrayElement<Records>
|
|
500
|
+
: Records extends readonly [
|
|
501
|
+
infer First extends UnknownRecord,
|
|
502
|
+
...infer Rest extends readonly UnknownRecord[],
|
|
503
|
+
]
|
|
504
|
+
? MergeAll<Rest, MergeTwo<Acc, First>>
|
|
505
|
+
: Acc;
|
|
506
|
+
}
|
|
@@ -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
|
});
|