1 | import type {IsEqual} from './is-equal';
|
2 | import type {ConditionalExcept} from './conditional-except';
|
3 | import type {ConditionalSimplifyDeep} from './conditional-simplify';
|
4 | import type {UnknownRecord} from './unknown-record';
|
5 | import type {EmptyObject} from './empty-object';
|
6 | import type {IsPlainObject} from './internal';
|
7 |
|
8 | /**
|
9 | Used to mark properties that should be excluded.
|
10 | */
|
11 | declare const conditionalPickDeepSymbol: unique symbol;
|
12 |
|
13 | /**
|
14 | Assert the condition according to the {@link ConditionalPickDeepOptions.condition|condition} option.
|
15 | */
|
16 | type AssertCondition<Type, Condition, Options extends ConditionalPickDeepOptions> = Options['condition'] extends 'equality'
|
17 | ? IsEqual<Type, Condition>
|
18 | : Type extends Condition
|
19 | ? true
|
20 | : false;
|
21 |
|
22 | /**
|
23 | ConditionalPickDeep options.
|
24 |
|
25 | @see ConditionalPickDeep
|
26 | */
|
27 | export type ConditionalPickDeepOptions = {
|
28 | /**
|
29 | The condition assertion mode.
|
30 |
|
31 | @default 'extends'
|
32 | */
|
33 | condition?: 'extends' | 'equality';
|
34 | };
|
35 |
|
36 | /**
|
37 | Pick keys recursively from the shape that matches the given condition.
|
38 |
|
39 | @see ConditionalPick
|
40 |
|
41 | @example
|
42 | ```
|
43 | import type {ConditionalPickDeep} from 'type-fest';
|
44 |
|
45 | interface Example {
|
46 | a: string;
|
47 | b: string | boolean;
|
48 | c: {
|
49 | d: string;
|
50 | e: {
|
51 | f?: string;
|
52 | g?: boolean;
|
53 | h: string | boolean;
|
54 | i: boolean | bigint;
|
55 | };
|
56 | j: boolean;
|
57 | };
|
58 | }
|
59 |
|
60 | type StringPick = ConditionalPickDeep<Example, string>;
|
61 | //=> {a: string; c: {d: string}}
|
62 |
|
63 | type StringPickOptional = ConditionalPickDeep<Example, string | undefined>;
|
64 | //=> {a: string; c: {d: string; e: {f?: string}}}
|
65 |
|
66 | type StringPickOptionalOnly = ConditionalPickDeep<Example, string | undefined, {condition: 'equality'}>;
|
67 | //=> {c: {e: {f?: string}}}
|
68 |
|
69 | type BooleanPick = ConditionalPickDeep<Example, boolean | undefined>;
|
70 | //=> {c: {e: {g?: boolean}; j: boolean}}
|
71 |
|
72 | type NumberPick = ConditionalPickDeep<Example, number>;
|
73 | //=> {}
|
74 |
|
75 | type StringOrBooleanPick = ConditionalPickDeep<Example, string | boolean>;
|
76 | //=> {
|
77 | // a: string;
|
78 | // b: string | boolean;
|
79 | // c: {
|
80 | // d: string;
|
81 | // e: {
|
82 | // h: string | boolean
|
83 | // };
|
84 | // j: boolean;
|
85 | // };
|
86 | // }
|
87 |
|
88 | type StringOrBooleanPickOnly = ConditionalPickDeep<Example, string | boolean, {condition: 'equality'}>;
|
89 | //=> {b: string | boolean; c: {e: {h: string | boolean}}}
|
90 | ```
|
91 |
|
92 | @category Object
|
93 | */
|
94 | export type ConditionalPickDeep<
|
95 | Type,
|
96 | Condition,
|
97 | Options extends ConditionalPickDeepOptions = {},
|
98 | > = ConditionalSimplifyDeep<ConditionalExcept<{
|
99 | [Key in keyof Type]: AssertCondition<Type[Key], Condition, Options> extends true
|
100 | ? Type[Key]
|
101 | : IsPlainObject<Type[Key]> extends true
|
102 | ? ConditionalPickDeep<Type[Key], Condition, Options>
|
103 | : typeof conditionalPickDeepSymbol;
|
104 | }, (typeof conditionalPickDeepSymbol | undefined) | EmptyObject>, never, UnknownRecord>;
|