forked from sindresorhus/type-fest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
undefined-on-partial-deep.d.ts
80 lines (72 loc) · 2.61 KB
/
undefined-on-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
import type {BuiltIns} from './internal';
/**
Create a deep version of another type where all optional keys are set to also accept `undefined`.
Note: This is only needed when the [`exactOptionalPropertyTypes`](https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes) TSConfig setting is enabled.
Use-cases:
- When `exactOptionalPropertyTypes` is enabled, an object like `{a: undefined}` is not assignable to the type `{a?: number}`. You can use `UndefinedOnPartialDeep<{a?: number}>` to make it assignable.
@example
```
import type {UndefinedOnPartialDeep} from 'type-fest';
interface Settings {
optionA: string;
optionB?: number;
subOption: {
subOptionA: boolean;
subOptionB?: boolean;
}
};
const testSettingsA: Settings = {
optionA: 'foo',
optionB: undefined, // TypeScript error if `exactOptionalPropertyTypes` is true.
subOption: {
subOptionA: true,
subOptionB: undefined, // TypeScript error if `exactOptionalPropertyTypes` is true
},
};
const testSettingsB: UndefinedOnPartialDeep<Settings> = {
optionA: 'foo',
optionB: undefined, // 👉 `optionB` can be set to undefined now.
subOption: {
subOptionA: true,
subOptionB: undefined, // 👉 `subOptionB` can be set to undefined now.
},
};
```
*/
export type UndefinedOnPartialDeep<T> =
// Handle built-in type and function
T extends BuiltIns | Function
? T
// Handle tuple and array
: T extends readonly unknown[]
? UndefinedOnPartialList<T>
// Handle map and readonly map
: T extends Map<infer K, infer V>
? Map<K, UndefinedOnPartialDeep<V>>
: T extends ReadonlyMap<infer K, infer V>
? ReadonlyMap<K, UndefinedOnPartialDeep<V>>
// Handle set and readonly set
: T extends Set<infer K>
? Set<UndefinedOnPartialDeep<K>>
: T extends ReadonlySet<infer K>
? ReadonlySet<UndefinedOnPartialDeep<K>>
// Handle object
: T extends Record<any, any>
? {
[KeyType in keyof T]: undefined extends T[KeyType]
? UndefinedOnPartialDeep<T[KeyType]> | undefined
: UndefinedOnPartialDeep<T[KeyType]>
}
: T; // If T is not builtins / function / array / map / set / object, return T
// Handle tuples and arrays
type UndefinedOnPartialList<T extends readonly unknown[]> = T extends []
? []
: T extends [infer F, ...infer R]
? [UndefinedOnPartialDeep<F>, ...UndefinedOnPartialDeep<R>]
: T extends readonly [infer F, ...infer R]
? readonly [UndefinedOnPartialDeep<F>, ...UndefinedOnPartialDeep<R>]
: T extends Array<infer F>
? Array<UndefinedOnPartialDeep<F>>
: T extends ReadonlyArray<infer F>
? ReadonlyArray<UndefinedOnPartialDeep<F>>
: never;