UNPKG

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