type-fest 4.8.2 → 4.9.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/index.d.ts +1 -0
- package/package.json +1 -1
- package/readme.md +1 -0
- package/source/conditional-pick-deep.d.ts +2 -1
- package/source/internal.d.ts +123 -4
- package/source/merge-deep.d.ts +17 -13
- package/source/paths.d.ts +4 -36
- package/source/shared-union-fields-deep.d.ts +192 -0
- package/source/writable-deep.d.ts +0 -1
package/index.d.ts
CHANGED
|
@@ -105,6 +105,7 @@ export type {ArrayIndices} from './source/array-indices';
|
|
|
105
105
|
export type {ArrayValues} from './source/array-values';
|
|
106
106
|
export type {SetFieldType} from './source/set-field-type';
|
|
107
107
|
export type {Paths} from './source/paths';
|
|
108
|
+
export type {SharedUnionFieldsDeep} from './source/shared-union-fields-deep';
|
|
108
109
|
|
|
109
110
|
// Template literal types
|
|
110
111
|
export type {CamelCase} from './source/camel-case';
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -179,6 +179,7 @@ Click the type names for complete docs.
|
|
|
179
179
|
- [`ArrayValues`](source/array-values.d.ts) - Provides all values for a constant array or tuple.
|
|
180
180
|
- [`SetFieldType`](source/set-field-type.d.ts) - Create a type that changes the type of the given keys.
|
|
181
181
|
- [`Paths`](source/paths.d.ts) - Generate a union of all possible paths to properties in the given object.
|
|
182
|
+
- [`SharedUnionFieldsDeep`](source/shared-union-fields-deep.d.ts) - Create a type with shared fields from a union of object types, deeply traversing nested structures.
|
|
182
183
|
|
|
183
184
|
### Type Guard
|
|
184
185
|
|
|
@@ -3,6 +3,7 @@ import type {ConditionalExcept} from './conditional-except';
|
|
|
3
3
|
import type {ConditionalSimplifyDeep} from './conditional-simplify';
|
|
4
4
|
import type {UnknownRecord} from './unknown-record';
|
|
5
5
|
import type {EmptyObject} from './empty-object';
|
|
6
|
+
import type {IsPlainObject} from './internal';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
Used to mark properties that should be excluded.
|
|
@@ -97,7 +98,7 @@ export type ConditionalPickDeep<
|
|
|
97
98
|
> = ConditionalSimplifyDeep<ConditionalExcept<{
|
|
98
99
|
[Key in keyof Type]: AssertCondition<Type[Key], Condition, Options> extends true
|
|
99
100
|
? Type[Key]
|
|
100
|
-
: Type[Key] extends
|
|
101
|
+
: IsPlainObject<Type[Key]> extends true
|
|
101
102
|
? ConditionalPickDeep<Type[Key], Condition, Options>
|
|
102
103
|
: typeof conditionalPickDeepSymbol;
|
|
103
104
|
}, (typeof conditionalPickDeepSymbol | undefined) | EmptyObject>, never, UnknownRecord>;
|
package/source/internal.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type {Simplify} from './simplify';
|
|
|
3
3
|
import type {Trim} from './trim';
|
|
4
4
|
import type {IsAny} from './is-any';
|
|
5
5
|
import type {UnknownRecord} from './unknown-record';
|
|
6
|
+
import type {IsNever} from './is-never';
|
|
7
|
+
import type {UnknownArray} from './unknown-array';
|
|
6
8
|
|
|
7
9
|
// TODO: Remove for v5.
|
|
8
10
|
export type {UnknownRecord} from './unknown-record';
|
|
@@ -12,7 +14,34 @@ Infer the length of the given array `<T>`.
|
|
|
12
14
|
|
|
13
15
|
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
|
|
14
16
|
*/
|
|
15
|
-
type
|
|
17
|
+
type ArrayLength<T extends readonly unknown[]> = T extends {readonly length: infer L} ? L : never;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
Infer the length of the given tuple `<T>`.
|
|
21
|
+
|
|
22
|
+
Returns `never` if the given type is an non-fixed-length array like `Array<string>`.
|
|
23
|
+
|
|
24
|
+
@example
|
|
25
|
+
```
|
|
26
|
+
type Tuple = TupleLength<[string, number, boolean]>;
|
|
27
|
+
//=> 3
|
|
28
|
+
|
|
29
|
+
type Array = TupleLength<string[]>;
|
|
30
|
+
//=> never
|
|
31
|
+
|
|
32
|
+
// Supports union types.
|
|
33
|
+
type Union = TupleLength<[] | [1, 2, 3] | Array<number>>;
|
|
34
|
+
//=> 1 | 3
|
|
35
|
+
```
|
|
36
|
+
*/
|
|
37
|
+
export type TupleLength<T extends UnknownArray> =
|
|
38
|
+
// `extends unknown` is used to convert `T` (if `T` is a union type) to
|
|
39
|
+
// a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types))
|
|
40
|
+
T extends unknown
|
|
41
|
+
? number extends T['length']
|
|
42
|
+
? never // Return never if the given type is an non-flexed-length array like `Array<string>`
|
|
43
|
+
: T['length']
|
|
44
|
+
: never; // Should never happen
|
|
16
45
|
|
|
17
46
|
/**
|
|
18
47
|
Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
|
|
@@ -63,19 +92,29 @@ the inferred tuple `U` and a tuple of length `B`, then extracts the length of tu
|
|
|
63
92
|
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
|
|
64
93
|
*/
|
|
65
94
|
export type Subtract<A extends number, B extends number> = BuildTuple<A> extends [...(infer U), ...BuildTuple<B>]
|
|
66
|
-
?
|
|
95
|
+
? ArrayLength<U>
|
|
67
96
|
: never;
|
|
68
97
|
|
|
69
98
|
/**
|
|
70
|
-
Matches any primitive, `Date`, or `RegExp` value.
|
|
99
|
+
Matches any primitive, `void`, `Date`, or `RegExp` value.
|
|
71
100
|
*/
|
|
72
|
-
export type BuiltIns = Primitive | Date | RegExp;
|
|
101
|
+
export type BuiltIns = Primitive | void | Date | RegExp;
|
|
73
102
|
|
|
74
103
|
/**
|
|
75
104
|
Matches non-recursive types.
|
|
76
105
|
*/
|
|
77
106
|
export type NonRecursiveType = BuiltIns | Function | (new (...args: any[]) => unknown);
|
|
78
107
|
|
|
108
|
+
/**
|
|
109
|
+
Returns a boolean for whether the given type is a plain key-value object.
|
|
110
|
+
*/
|
|
111
|
+
export type IsPlainObject<T> =
|
|
112
|
+
T extends NonRecursiveType | UnknownArray | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
|
|
113
|
+
? false
|
|
114
|
+
: T extends object
|
|
115
|
+
? true
|
|
116
|
+
: false;
|
|
117
|
+
|
|
79
118
|
export type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
|
|
80
119
|
|
|
81
120
|
export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
|
@@ -317,3 +356,83 @@ IsPrimitive<Object>
|
|
|
317
356
|
```
|
|
318
357
|
*/
|
|
319
358
|
export type IsPrimitive<T> = [T] extends [Primitive] ? true : false;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
Returns the static, fixed-length portion of the given array, excluding variable-length parts.
|
|
362
|
+
|
|
363
|
+
@example
|
|
364
|
+
```
|
|
365
|
+
type A = [string, number, boolean, ...string[]];
|
|
366
|
+
type B = StaticPartOfArray<A>;
|
|
367
|
+
//=> [string, number, boolean]
|
|
368
|
+
```
|
|
369
|
+
*/
|
|
370
|
+
export type StaticPartOfArray<T extends UnknownArray, Result extends UnknownArray = []> =
|
|
371
|
+
T extends unknown
|
|
372
|
+
? number extends T['length'] ?
|
|
373
|
+
T extends readonly [infer U, ...infer V]
|
|
374
|
+
? StaticPartOfArray<V, [...Result, U]>
|
|
375
|
+
: Result
|
|
376
|
+
: T
|
|
377
|
+
: never; // Should never happen
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
Returns the variable, non-fixed-length portion of the given array, excluding static-length parts.
|
|
381
|
+
|
|
382
|
+
@example
|
|
383
|
+
```
|
|
384
|
+
type A = [string, number, boolean, ...string[]];
|
|
385
|
+
type B = VariablePartOfArray<A>;
|
|
386
|
+
//=> string[]
|
|
387
|
+
```
|
|
388
|
+
*/
|
|
389
|
+
export type VariablePartOfArray<T extends UnknownArray> =
|
|
390
|
+
T extends unknown
|
|
391
|
+
? T extends readonly [...StaticPartOfArray<T>, ...infer U]
|
|
392
|
+
? U
|
|
393
|
+
: []
|
|
394
|
+
: never; // Should never happen
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
Returns the minimum number in the given union of numbers.
|
|
398
|
+
|
|
399
|
+
Note: Just supports numbers from 0 to 999.
|
|
400
|
+
|
|
401
|
+
@example
|
|
402
|
+
```
|
|
403
|
+
type A = UnionMin<3 | 1 | 2>;
|
|
404
|
+
//=> 1
|
|
405
|
+
```
|
|
406
|
+
*/
|
|
407
|
+
export type UnionMin<N extends number> = InternalUnionMin<N>;
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
The actual implementation of `UnionMin`. It's private because it has some arguments that don't need to be exposed.
|
|
411
|
+
*/
|
|
412
|
+
type InternalUnionMin<N extends number, T extends UnknownArray = []> =
|
|
413
|
+
T['length'] extends N
|
|
414
|
+
? T['length']
|
|
415
|
+
: InternalUnionMin<N, [...T, unknown]>;
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
Returns the maximum number in the given union of numbers.
|
|
419
|
+
|
|
420
|
+
Note: Just supports numbers from 0 to 999.
|
|
421
|
+
|
|
422
|
+
@example
|
|
423
|
+
```
|
|
424
|
+
type A = UnionMax<1 | 3 | 2>;
|
|
425
|
+
//=> 3
|
|
426
|
+
```
|
|
427
|
+
*/
|
|
428
|
+
export type UnionMax<N extends number> = InternalUnionMax<N>;
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
The actual implementation of `UnionMax`. It's private because it has some arguments that don't need to be exposed.
|
|
432
|
+
*/
|
|
433
|
+
type InternalUnionMax<N extends number, T extends UnknownArray = []> =
|
|
434
|
+
IsNever<N> extends true
|
|
435
|
+
? T['length']
|
|
436
|
+
: T['length'] extends N
|
|
437
|
+
? InternalUnionMax<Exclude<N, T['length']>, T>
|
|
438
|
+
: InternalUnionMax<N, [...T, unknown]>;
|
package/source/merge-deep.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {ConditionalSimplifyDeep} from './conditional-simplify';
|
|
2
2
|
import type {OmitIndexSignature} from './omit-index-signature';
|
|
3
3
|
import type {PickIndexSignature} from './pick-index-signature';
|
|
4
|
-
import type {EnforceOptional} from './enforce-optional';
|
|
5
4
|
import type {Merge} from './merge';
|
|
6
5
|
import type {
|
|
7
6
|
ArrayTail,
|
|
@@ -30,23 +29,28 @@ type MergeDeepRecordProperty<
|
|
|
30
29
|
|
|
31
30
|
/**
|
|
32
31
|
Walk through the union of the keys of the two objects and test in which object the properties are defined.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
Rules:
|
|
33
|
+
1. If the source does not contain the key, the value of the destination is returned.
|
|
34
|
+
2. If the source contains the key and the destination does not contain the key, the value of the source is returned.
|
|
35
|
+
3. If both contain the key, try to merge according to the chosen {@link MergeDeepOptions options} or return the source if unable to merge.
|
|
36
36
|
*/
|
|
37
37
|
type DoMergeDeepRecord<
|
|
38
38
|
Destination extends UnknownRecord,
|
|
39
39
|
Source extends UnknownRecord,
|
|
40
40
|
Options extends MergeDeepInternalOptions,
|
|
41
|
-
> =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
41
|
+
> =
|
|
42
|
+
// Case in rule 1: The destination contains the key but the source doesn't.
|
|
43
|
+
{
|
|
44
|
+
[Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key];
|
|
45
|
+
}
|
|
46
|
+
// Case in rule 2: The source contains the key but the destination doesn't.
|
|
47
|
+
& {
|
|
48
|
+
[Key in keyof Source as Key extends keyof Destination ? never : Key]: Source[Key];
|
|
49
|
+
}
|
|
50
|
+
// Case in rule 3: Both the source and the destination contain the key.
|
|
51
|
+
& {
|
|
52
|
+
[Key in keyof Source as Key extends keyof Destination ? Key : never]: MergeDeepRecordProperty<Destination[Key], Source[Key], Options>;
|
|
53
|
+
};
|
|
50
54
|
|
|
51
55
|
/**
|
|
52
56
|
Wrapper around {@link DoMergeDeepRecord} which preserves index signatures.
|
package/source/paths.d.ts
CHANGED
|
@@ -1,41 +1,9 @@
|
|
|
1
|
-
import type {NonRecursiveType, ToString} from './internal';
|
|
1
|
+
import type {StaticPartOfArray, VariablePartOfArray, NonRecursiveType, ToString} from './internal';
|
|
2
2
|
import type {EmptyObject} from './empty-object';
|
|
3
3
|
import type {IsAny} from './is-any';
|
|
4
4
|
import type {IsNever} from './is-never';
|
|
5
5
|
import type {UnknownArray} from './unknown-array';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
Return the part of the given array with a fixed index.
|
|
9
|
-
|
|
10
|
-
@example
|
|
11
|
-
```
|
|
12
|
-
type A = [string, number, boolean, ...string[]];
|
|
13
|
-
type B = FilterFixedIndexArray<A>;
|
|
14
|
-
//=> [string, number, boolean]
|
|
15
|
-
```
|
|
16
|
-
*/
|
|
17
|
-
type FilterFixedIndexArray<T extends UnknownArray, Result extends UnknownArray = []> =
|
|
18
|
-
number extends T['length'] ?
|
|
19
|
-
T extends readonly [infer U, ...infer V]
|
|
20
|
-
? FilterFixedIndexArray<V, [...Result, U]>
|
|
21
|
-
: Result
|
|
22
|
-
: T;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
Return the part of the given array with a non-fixed index.
|
|
26
|
-
|
|
27
|
-
@example
|
|
28
|
-
```
|
|
29
|
-
type A = [string, number, boolean, ...string[]];
|
|
30
|
-
type B = FilterNotFixedIndexArray<A>;
|
|
31
|
-
//=> string[]
|
|
32
|
-
```
|
|
33
|
-
*/
|
|
34
|
-
type FilterNotFixedIndexArray<T extends UnknownArray> =
|
|
35
|
-
T extends readonly [...FilterFixedIndexArray<T>, ...infer U]
|
|
36
|
-
? U
|
|
37
|
-
: [];
|
|
38
|
-
|
|
39
7
|
/**
|
|
40
8
|
Generate a union of all possible paths to properties in the given object.
|
|
41
9
|
|
|
@@ -78,15 +46,15 @@ open('listB.1'); // TypeError. Because listB only has one element.
|
|
|
78
46
|
@category Array
|
|
79
47
|
*/
|
|
80
48
|
export type Paths<T> =
|
|
81
|
-
T extends NonRecursiveType
|
|
49
|
+
T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
|
|
82
50
|
? never
|
|
83
51
|
: IsAny<T> extends true
|
|
84
52
|
? never
|
|
85
53
|
: T extends UnknownArray
|
|
86
54
|
? number extends T['length']
|
|
87
55
|
// We need to handle the fixed and non-fixed index part of the array separately.
|
|
88
|
-
? InternalPaths<
|
|
89
|
-
| InternalPaths<Array<
|
|
56
|
+
? InternalPaths<StaticPartOfArray<T>>
|
|
57
|
+
| InternalPaths<Array<VariablePartOfArray<T>[number]>>
|
|
90
58
|
: InternalPaths<T>
|
|
91
59
|
: T extends object
|
|
92
60
|
? InternalPaths<T>
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type {NonRecursiveType, UnionMin, UnionMax, TupleLength, StaticPartOfArray, VariablePartOfArray} from './internal';
|
|
2
|
+
import type {IsNever} from './is-never';
|
|
3
|
+
import type {UnknownArray} from './unknown-array';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
|
|
7
|
+
|
|
8
|
+
@example
|
|
9
|
+
```
|
|
10
|
+
type ReadonlyArray = readonly string[];
|
|
11
|
+
type NormalArray = string[];
|
|
12
|
+
|
|
13
|
+
type ReadonlyResult = SetArrayAccess<NormalArray, true>;
|
|
14
|
+
//=> readonly string[]
|
|
15
|
+
|
|
16
|
+
type NormalResult = SetArrayAccess<ReadonlyArray, false>;
|
|
17
|
+
//=> string[]
|
|
18
|
+
```
|
|
19
|
+
*/
|
|
20
|
+
type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
|
|
21
|
+
T extends readonly [...infer U] ?
|
|
22
|
+
IsReadonly extends true
|
|
23
|
+
? readonly [...U]
|
|
24
|
+
: [...U]
|
|
25
|
+
: T;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
Returns whether the given array `T` is readonly.
|
|
29
|
+
*/
|
|
30
|
+
type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
SharedUnionFieldsDeep options.
|
|
34
|
+
|
|
35
|
+
@see {@link SharedUnionFieldsDeep}
|
|
36
|
+
*/
|
|
37
|
+
export type SharedUnionFieldsDeepOptions = {
|
|
38
|
+
/**
|
|
39
|
+
When set to true, this option impacts each element within arrays or tuples. If all union values are arrays or tuples, it constructs an array of the shortest possible length, ensuring every element exists in the union array.
|
|
40
|
+
|
|
41
|
+
@default false
|
|
42
|
+
*/
|
|
43
|
+
recurseIntoArrays?: boolean;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
Create a type with shared fields from a union of object types, deeply traversing nested structures.
|
|
48
|
+
|
|
49
|
+
Use the {@link SharedUnionFieldsDeepOptions `Options`} to specify the behavior for arrays.
|
|
50
|
+
|
|
51
|
+
Use-cases:
|
|
52
|
+
- You want a safe object type where each key exists in the union object.
|
|
53
|
+
- You want to focus on the common fields of the union type and don't want to have to care about the other fields.
|
|
54
|
+
|
|
55
|
+
@example
|
|
56
|
+
```
|
|
57
|
+
import type {SharedUnionFieldsDeep} from 'type-fest';
|
|
58
|
+
|
|
59
|
+
type Cat = {
|
|
60
|
+
info: {
|
|
61
|
+
name: string;
|
|
62
|
+
type: 'cat';
|
|
63
|
+
catType: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
type Dog = {
|
|
68
|
+
info: {
|
|
69
|
+
name: string;
|
|
70
|
+
type: 'dog';
|
|
71
|
+
dogType: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
function displayPetInfo(petInfo: (Cat | Dog)['info']) {
|
|
76
|
+
// typeof petInfo =>
|
|
77
|
+
// {
|
|
78
|
+
// name: string;
|
|
79
|
+
// type: 'cat';
|
|
80
|
+
// catType: string; // Needn't care about this field, because it's not a common pet info field.
|
|
81
|
+
// } | {
|
|
82
|
+
// name: string;
|
|
83
|
+
// type: 'dog';
|
|
84
|
+
// dogType: string; // Needn't care about this field, because it's not a common pet info field.
|
|
85
|
+
// }
|
|
86
|
+
|
|
87
|
+
// petInfo type is complex and have some needless fields
|
|
88
|
+
|
|
89
|
+
console.log('name: ', petInfo.name);
|
|
90
|
+
console.log('type: ', petInfo.type);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
|
|
94
|
+
// typeof petInfo =>
|
|
95
|
+
// {
|
|
96
|
+
// name: string;
|
|
97
|
+
// type: 'cat' | 'dog';
|
|
98
|
+
// }
|
|
99
|
+
|
|
100
|
+
// petInfo type is simple and clear
|
|
101
|
+
|
|
102
|
+
console.log('name: ', petInfo.name);
|
|
103
|
+
console.log('type: ', petInfo.type);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
@category Object
|
|
108
|
+
@category Union
|
|
109
|
+
*/
|
|
110
|
+
export type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {recurseIntoArrays: false}> =
|
|
111
|
+
// `Union extends` will convert `Union`
|
|
112
|
+
// to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
|
|
113
|
+
// But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
|
|
114
|
+
[Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
|
|
115
|
+
? Union
|
|
116
|
+
: [Union] extends [UnknownArray]
|
|
117
|
+
? Options['recurseIntoArrays'] extends true
|
|
118
|
+
? SetArrayAccess<SharedArrayUnionFieldsDeep<Union, Options>, IsArrayReadonly<Union>>
|
|
119
|
+
: Union
|
|
120
|
+
: [Union] extends [object]
|
|
121
|
+
? SharedObjectUnionFieldsDeep<Union, Options>
|
|
122
|
+
: Union;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
Same as `SharedUnionFieldsDeep`, but accepts only `object`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
|
|
126
|
+
*/
|
|
127
|
+
type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions> =
|
|
128
|
+
keyof Union extends infer Keys
|
|
129
|
+
? IsNever<Keys> extends false
|
|
130
|
+
? {
|
|
131
|
+
[Key in keyof Union]:
|
|
132
|
+
Union[Key] extends NonRecursiveType
|
|
133
|
+
? Union[Key]
|
|
134
|
+
: SharedUnionFieldsDeep<Union[Key], Options>
|
|
135
|
+
}
|
|
136
|
+
: {}
|
|
137
|
+
: Union;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
Same as `SharedUnionFieldsDeep`, but accepts only `UnknownArray`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
|
|
141
|
+
*/
|
|
142
|
+
type SharedArrayUnionFieldsDeep<Union extends UnknownArray, Options extends SharedUnionFieldsDeepOptions> =
|
|
143
|
+
// Restore the readonly modifier of the array.
|
|
144
|
+
SetArrayAccess<
|
|
145
|
+
InternalSharedArrayUnionFieldsDeep<Union, Options>,
|
|
146
|
+
IsArrayReadonly<Union>
|
|
147
|
+
>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
Internal helper for `SharedArrayUnionFieldsDeep`. Needn't care the `readonly` modifier of arrays.
|
|
151
|
+
*/
|
|
152
|
+
type InternalSharedArrayUnionFieldsDeep<
|
|
153
|
+
Union extends UnknownArray,
|
|
154
|
+
Options extends SharedUnionFieldsDeepOptions,
|
|
155
|
+
ResultTuple extends UnknownArray = [],
|
|
156
|
+
> =
|
|
157
|
+
// We should build a minimum possible length tuple where each element in the tuple exists in the union tuple.
|
|
158
|
+
IsNever<TupleLength<Union>> extends true
|
|
159
|
+
// Rule 1: If all the arrays in the union have non-fixed lengths,
|
|
160
|
+
// like `Array<string> | [number, ...string[]]`
|
|
161
|
+
// we should build a tuple that is [the_fixed_parts_of_union, ...the_rest_of_union[]].
|
|
162
|
+
// For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, ...string[]]>`
|
|
163
|
+
// => `[string | number, ...string[]]`.
|
|
164
|
+
? ResultTuple['length'] extends UnionMax<StaticPartOfArray<Union>['length']>
|
|
165
|
+
? [
|
|
166
|
+
// The fixed-length part of the tuple.
|
|
167
|
+
...ResultTuple,
|
|
168
|
+
// The rest of the union.
|
|
169
|
+
// Due to `ResultTuple` is the maximum possible fixed-length part of the tuple,
|
|
170
|
+
// so we can use `StaticPartOfArray` to get the rest of the union.
|
|
171
|
+
...Array<
|
|
172
|
+
SharedUnionFieldsDeep<VariablePartOfArray<Union>[number], Options>
|
|
173
|
+
>,
|
|
174
|
+
]
|
|
175
|
+
// Build the fixed-length tuple recursively.
|
|
176
|
+
: InternalSharedArrayUnionFieldsDeep<
|
|
177
|
+
Union, Options,
|
|
178
|
+
[...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
|
|
179
|
+
>
|
|
180
|
+
// Rule 2: If at least one of the arrays in the union have fixed lengths,
|
|
181
|
+
// like `Array<string> | [number, string]`,
|
|
182
|
+
// we should build a tuple of the smallest possible length to ensure any
|
|
183
|
+
// item in the result tuple exists in the union tuple.
|
|
184
|
+
// For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, string]>`
|
|
185
|
+
// => `[string | number, string]`.
|
|
186
|
+
: ResultTuple['length'] extends UnionMin<TupleLength<Union>>
|
|
187
|
+
? ResultTuple
|
|
188
|
+
// As above, build tuple recursively.
|
|
189
|
+
: InternalSharedArrayUnionFieldsDeep<
|
|
190
|
+
Union, Options,
|
|
191
|
+
[...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
|
|
192
|
+
>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {BuiltIns, HasMultipleCallSignatures} from './internal';
|
|
2
|
-
import type {Writable} from './writable.js';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
Create a deeply mutable version of an `object`/`ReadonlyMap`/`ReadonlySet`/`ReadonlyArray` type. The inverse of `ReadonlyDeep<T>`. Use `Writable<T>` if you only need one level deep.
|