UNPKG

2.71 kBTypeScriptView Raw
1import type {BuiltIns} from './internal';
2import type {Merge} from './merge';
3
4/**
5Create a deep version of another type where all optional keys are set to also accept `undefined`.
6
7Note: This is only needed when the [`exactOptionalPropertyTypes`](https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes) TSConfig setting is enabled.
8
9Use-cases:
10- 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.
11
12@example
13```
14import type {UndefinedOnPartialDeep} from 'type-fest';
15
16interface Settings {
17 optionA: string;
18 optionB?: number;
19 subOption: {
20 subOptionA: boolean;
21 subOptionB?: boolean;
22 }
23};
24
25const testSettingsA: Settings = {
26 optionA: 'foo',
27 optionB: undefined, // TypeScript error if `exactOptionalPropertyTypes` is true.
28 subOption: {
29 subOptionA: true,
30 subOptionB: undefined, // TypeScript error if `exactOptionalPropertyTypes` is true
31 },
32};
33
34const testSettingsB: UndefinedOnPartialDeep<Settings> = {
35 optionA: 'foo',
36 optionB: undefined, // 👉 `optionB` can be set to undefined now.
37 subOption: {
38 subOptionA: true,
39 subOptionB: undefined, // 👉 `subOptionB` can be set to undefined now.
40 },
41};
42```
43*/
44export type UndefinedOnPartialDeep<T> =
45 // Handle built-in type and function
46 T extends BuiltIns | Function
47 ? T
48 // Handle tuple and array
49 : T extends readonly unknown[]
50 ? UndefinedOnPartialList<T>
51 // Handle map and readonly map
52 : T extends Map<infer K, infer V>
53 ? Map<K, UndefinedOnPartialDeep<V>>
54 : T extends ReadonlyMap<infer K, infer V>
55 ? ReadonlyMap<K, UndefinedOnPartialDeep<V>>
56 // Handle set and readonly set
57 : T extends Set<infer K>
58 ? Set<UndefinedOnPartialDeep<K>>
59 : T extends ReadonlySet<infer K>
60 ? ReadonlySet<UndefinedOnPartialDeep<K>>
61 // Handle object
62 : T extends Record<any, any>
63 ? {
64 [KeyType in keyof T]: undefined extends T[KeyType]
65 ? UndefinedOnPartialDeep<T[KeyType]> | undefined
66 : UndefinedOnPartialDeep<T[KeyType]>
67 }
68 : T; // If T is not builtins / function / array / map / set / object, return T
69
70// Handle tuples and arrays
71type UndefinedOnPartialList<T extends readonly unknown[]> = T extends []
72 ? []
73 : T extends [infer F, ...infer R]
74 ? [UndefinedOnPartialDeep<F>, ...UndefinedOnPartialDeep<R>]
75 : T extends readonly [infer F, ...infer R]
76 ? readonly [UndefinedOnPartialDeep<F>, ...UndefinedOnPartialDeep<R>]
77 : T extends Array<infer F>
78 ? Array<UndefinedOnPartialDeep<F>>
79 : T extends ReadonlyArray<infer F>
80 ? ReadonlyArray<UndefinedOnPartialDeep<F>>
81 : never;