-
-
Notifications
You must be signed in to change notification settings - Fork 570
/
Copy pathpartial-deep.d.ts
137 lines (110 loc) · 4.77 KB
/
partial-deep.d.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import type {BuiltIns} from './internal';
/**
@see {@link PartialDeep}
*/
export type PartialDeepOptions = {
/**
Whether to affect the individual elements of arrays and tuples.
@default false
*/
readonly recurseIntoArrays?: boolean;
/**
Allows `undefined` values in non-tuple arrays.
- When set to `true`, elements of non-tuple arrays can be `undefined`.
- When set to `false`, only explicitly defined elements are allowed in non-tuple arrays, ensuring stricter type checking.
@default true
@example
You can prevent `undefined` values in non-tuple arrays by passing `{recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}` as the second type argument:
```
import type {PartialDeep} from 'type-fest';
type Settings = {
languages: string[];
};
declare const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}>;
partialSettings.languages = [undefined]; // Error
partialSettings.languages = []; // Ok
```
*/
readonly allowUndefinedInNonTupleArrays?: boolean;
};
/**
Create a type from another type with all keys and nested keys set to optional.
Use-cases:
- Merging a default settings/config object with another object, the second object would be a deep partial of the default object.
- Mocking and testing complex entities, where populating an entire object with its keys would be redundant in terms of the mock or test.
@example
```
import type {PartialDeep} from 'type-fest';
const settings: Settings = {
textEditor: {
fontSize: 14,
fontColor: '#000000',
fontWeight: 400
},
autocomplete: false,
autosave: true
};
const applySavedSettings = (savedSettings: PartialDeep<Settings>) => {
return {...settings, ...savedSettings};
}
settings = applySavedSettings({textEditor: {fontWeight: 500}});
```
By default, this does not affect elements in array and tuple types. You can change this by passing `{recurseIntoArrays: true}` as the second type argument:
```
import type {PartialDeep} from 'type-fest';
type Settings = {
languages: string[];
}
const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
languages: [undefined]
};
```
@see {@link PartialDeepOptions}
@category Object
@category Array
@category Set
@category Map
*/
export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns | (((...arguments_: any[]) => unknown)) | (new (...arguments_: any[]) => unknown)
? T
: T extends Map<infer KeyType, infer ValueType>
? PartialMapDeep<KeyType, ValueType, Options>
: T extends Set<infer ItemType>
? PartialSetDeep<ItemType, Options>
: T extends ReadonlyMap<infer KeyType, infer ValueType>
? PartialReadonlyMapDeep<KeyType, ValueType, Options>
: T extends ReadonlySet<infer ItemType>
? PartialReadonlySetDeep<ItemType, Options>
: T extends object
? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
? Options['recurseIntoArrays'] extends true
? ItemType[] extends T // Test for arrays (non-tuples) specifically
? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
? ReadonlyArray<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
: Array<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
: PartialObjectDeep<T, Options> // Tuples behave properly
: T // If they don't opt into array testing, just use the original type
: PartialObjectDeep<T, Options>
: unknown;
/**
Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
*/
type PartialMapDeep<KeyType, ValueType, Options extends PartialDeepOptions> = {} & Map<PartialDeep<KeyType, Options>, PartialDeep<ValueType, Options>>;
/**
Same as `PartialDeep`, but accepts only `Set`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialSetDeep<T, Options extends PartialDeepOptions> = {} & Set<PartialDeep<T, Options>>;
/**
Same as `PartialDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialReadonlyMapDeep<KeyType, ValueType, Options extends PartialDeepOptions> = {} & ReadonlyMap<PartialDeep<KeyType, Options>, PartialDeep<ValueType, Options>>;
/**
Same as `PartialDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialReadonlySetDeep<T, Options extends PartialDeepOptions> = {} & ReadonlySet<PartialDeep<T, Options>>;
/**
Same as `PartialDeep`, but accepts only `object`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialObjectDeep<ObjectType extends object, Options extends PartialDeepOptions> = {
[KeyType in keyof ObjectType]?: PartialDeep<ObjectType[KeyType], Options>
};