UNPKG

4.14 kBTypeScriptView Raw
1import type {BuildObject, BuildTuple, NonRecursiveType, ObjectValue} from './internal';
2import type {IsNever} from './is-never';
3import type {Paths} from './paths';
4import type {Simplify} from './simplify.d';
5import type {UnionToIntersection} from './union-to-intersection.d';
6import type {UnknownArray} from './unknown-array';
7
8/**
9Pick properties from a deeply-nested object.
10
11It supports recursing into arrays.
12
13Use-case: Distill complex objects down to the components you need to target.
14
15@example
16```
17import type {PickDeep, PartialDeep} from 'type-fest';
18
19type Configuration = {
20 userConfig: {
21 name: string;
22 age: number;
23 address: [
24 {
25 city1: string;
26 street1: string;
27 },
28 {
29 city2: string;
30 street2: string;
31 }
32 ]
33 };
34 otherConfig: any;
35};
36
37type NameConfig = PickDeep<Configuration, 'userConfig.name'>;
38// type NameConfig = {
39// userConfig: {
40// name: string;
41// }
42// };
43
44// Supports optional properties
45type User = PickDeep<PartialDeep<Configuration>, 'userConfig.name' | 'userConfig.age'>;
46// type User = {
47// userConfig?: {
48// name?: string;
49// age?: number;
50// };
51// };
52
53// Supports array
54type AddressConfig = PickDeep<Configuration, 'userConfig.address.0'>;
55// type AddressConfig = {
56// userConfig: {
57// address: [{
58// city1: string;
59// street1: string;
60// }];
61// };
62// }
63
64// Supports recurse into array
65type Street = PickDeep<Configuration, 'userConfig.address.1.street2'>;
66// type Street = {
67// userConfig: {
68// address: [
69// unknown,
70// {street2: string}
71// ];
72// };
73// }
74```
75
76@category Object
77@category Array
78*/
79export type PickDeep<T, PathUnion extends Paths<T>> =
80 T extends NonRecursiveType
81 ? never
82 : T extends UnknownArray
83 ? UnionToIntersection<{
84 [P in PathUnion]: InternalPickDeep<T, P>;
85 }[PathUnion]
86 >
87 : T extends object
88 ? Simplify<UnionToIntersection<{
89 [P in PathUnion]: InternalPickDeep<T, P>;
90 }[PathUnion]>>
91 : never;
92
93/**
94Pick an object/array from the given object/array by one path.
95*/
96type InternalPickDeep<T, Path extends string | number> =
97 T extends NonRecursiveType
98 ? never
99 : T extends UnknownArray ? PickDeepArray<T, Path>
100 : T extends object ? Simplify<PickDeepObject<T, Path>>
101 : never;
102
103/**
104Pick an object from the given object by one path.
105*/
106type PickDeepObject<RecordType extends object, P extends string | number> =
107 P extends `${infer RecordKeyInPath}.${infer SubPath}`
108 ? ObjectValue<RecordType, RecordKeyInPath> extends infer ObjectV
109 ? IsNever<ObjectV> extends false
110 ? BuildObject<RecordKeyInPath, InternalPickDeep<NonNullable<ObjectV>, SubPath>, RecordType>
111 : never
112 : never
113 : ObjectValue<RecordType, P> extends infer ObjectV
114 ? IsNever<ObjectV> extends false
115 ? BuildObject<P, ObjectV, RecordType>
116 : never
117 : never;
118
119/**
120Pick an array from the given array by one path.
121*/
122type PickDeepArray<ArrayType extends UnknownArray, P extends string | number> =
123 // Handle paths that are `${number}.${string}`
124 P extends `${infer ArrayIndex extends number}.${infer SubPath}`
125 // When `ArrayIndex` is equal to `number`
126 ? number extends ArrayIndex
127 ? ArrayType extends unknown[]
128 ? Array<InternalPickDeep<NonNullable<ArrayType[number]>, SubPath>>
129 : ArrayType extends readonly unknown[]
130 ? ReadonlyArray<InternalPickDeep<NonNullable<ArrayType[number]>, SubPath>>
131 : never
132 // When `ArrayIndex` is a number literal
133 : ArrayType extends unknown[]
134 ? [...BuildTuple<ArrayIndex>, InternalPickDeep<NonNullable<ArrayType[ArrayIndex]>, SubPath>]
135 : ArrayType extends readonly unknown[]
136 ? readonly [...BuildTuple<ArrayIndex>, InternalPickDeep<NonNullable<ArrayType[ArrayIndex]>, SubPath>]
137 : never
138 // When the path is equal to `number`
139 : P extends `${infer ArrayIndex extends number}`
140 // When `ArrayIndex` is `number`
141 ? number extends ArrayIndex
142 ? ArrayType
143 // When `ArrayIndex` is a number literal
144 : ArrayType extends unknown[]
145 ? [...BuildTuple<ArrayIndex>, ArrayType[ArrayIndex]]
146 : ArrayType extends readonly unknown[]
147 ? readonly [...BuildTuple<ArrayIndex>, ArrayType[ArrayIndex]]
148 : never
149 : never;