UNPKG

2.75 kBTypeScriptView Raw
1import type {IfUnknown} from './if-unknown';
2import type {BuiltIns, LiteralKeyOf} from './internal';
3import type {Merge} from './merge';
4
5/**
6@see PartialOnUndefinedDeep
7*/
8export type PartialOnUndefinedDeepOptions = {
9 /**
10 Whether to affect the individual elements of arrays and tuples.
11
12 @default false
13 */
14 readonly recurseIntoArrays?: boolean;
15};
16
17/**
18Create a deep version of another type where all keys accepting `undefined` type are set to optional.
19
20This utility type is recursive, transforming at any level deep. By default, it does not affect arrays and tuples items unless you explicitly pass `{recurseIntoArrays: true}` as the second type argument.
21
22Use-cases:
23- Make all properties of a type that can be undefined optional to not have to specify keys with undefined value.
24
25@example
26```
27import type {PartialOnUndefinedDeep} from 'type-fest';
28
29interface Settings {
30 optionA: string;
31 optionB: number | undefined;
32 subOption: {
33 subOptionA: boolean;
34 subOptionB: boolean | undefined;
35 }
36};
37
38const testSettings: PartialOnUndefinedDeep<Settings> = {
39 optionA: 'foo',
40 // 👉 optionB is now optional and can be omitted
41 subOption: {
42 subOptionA: true,
43 // 👉 subOptionB is now optional as well and can be omitted
44 },
45};
46```
47
48@category Object
49*/
50export type PartialOnUndefinedDeep<T, Options extends PartialOnUndefinedDeepOptions = {}> = T extends Record<any, any> | undefined
51 ? {[KeyType in keyof T as undefined extends T[KeyType] ? IfUnknown<T[KeyType], never, KeyType> : never]?: PartialOnUndefinedDeepValue<T[KeyType], Options>} extends infer U // Make a partial type with all value types accepting undefined (and set them optional)
52 ? Merge<{[KeyType in keyof T as KeyType extends LiteralKeyOf<U> ? never : KeyType]: PartialOnUndefinedDeepValue<T[KeyType], Options>}, U> // Join all remaining keys not treated in U
53 : never // Should not happen
54 : T;
55
56/**
57Utility type to get the value type by key and recursively call `PartialOnUndefinedDeep` to transform sub-objects.
58*/
59type PartialOnUndefinedDeepValue<T, Options extends PartialOnUndefinedDeepOptions> = T extends BuiltIns | ((...arguments_: any[]) => unknown)
60 ? T
61 : T extends ReadonlyArray<infer U> // Test if type is array or tuple
62 ? Options['recurseIntoArrays'] extends true // Check if option is activated
63 ? U[] extends T // Check if array not tuple
64 ? readonly U[] extends T
65 ? ReadonlyArray<PartialOnUndefinedDeep<U, Options>> // Readonly array treatment
66 : Array<PartialOnUndefinedDeep<U, Options>> // Mutable array treatment
67 : PartialOnUndefinedDeep<{[Key in keyof T]: PartialOnUndefinedDeep<T[Key], Options>}, Options> // Tuple treatment
68 : T
69 : T extends Record<any, any> | undefined
70 ? PartialOnUndefinedDeep<T, Options>
71 : unknown;
72
\No newline at end of file