UNPKG

4.03 kBTypeScriptView Raw
1import type {ArraySplice} from './array-splice';
2import type {ExactKey, IsArrayReadonly, NonRecursiveType, SetArrayAccess, ToString} from './internal';
3import type {IsEqual} from './is-equal';
4import type {IsNever} from './is-never';
5import type {LiteralUnion} from './literal-union';
6import type {Paths} from './paths';
7import type {SharedUnionFieldsDeep} from './shared-union-fields-deep';
8import type {SimplifyDeep} from './simplify-deep';
9import type {UnknownArray} from './unknown-array';
10
11/**
12Omit properties from a deeply-nested object.
13
14It supports recursing into arrays.
15
16It supports removing specific items from an array, replacing each removed item with unknown at the specified index.
17
18Use-case: Remove unneeded parts of complex objects.
19
20Use [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) if you only need one level deep.
21
22@example
23```
24import type {OmitDeep} from 'type-fest';
25
26type Info = {
27 userInfo: {
28 name: string;
29 uselessInfo: {
30 foo: string;
31 };
32 };
33};
34
35type UsefulInfo = OmitDeep<Info, 'userInfo.uselessInfo'>;
36// type UsefulInfo = {
37// userInfo: {
38// name: string;
39// };
40// };
41
42// Supports removing multiple paths
43type Info1 = {
44 userInfo: {
45 name: string;
46 uselessField: string;
47 uselessInfo: {
48 foo: string;
49 };
50 };
51};
52
53type UsefulInfo1 = OmitDeep<Info1, 'userInfo.uselessInfo' | 'userInfo.uselessField'>;
54// type UsefulInfo1 = {
55// userInfo: {
56// name: string;
57// };
58// };
59
60// Supports array
61type A = OmitDeep<[1, 'foo', 2], 1>;
62// type A = [1, unknown, 2];
63
64// Supports recursing into array
65
66type Info1 = {
67 address: [
68 {
69 street: string
70 },
71 {
72 street2: string,
73 foo: string
74 };
75 ];
76}
77type AddressInfo = OmitDeep<Info1, 'address.1.foo'>;
78// type AddressInfo = {
79// address: [
80// {
81// street: string;
82// },
83// {
84// street2: string;
85// };
86// ];
87// };
88```
89
90@category Object
91@category Array
92*/
93export type OmitDeep<T, PathUnion extends LiteralUnion<Paths<T>, string>> =
94 SimplifyDeep<
95 SharedUnionFieldsDeep<
96 {[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion]
97 >,
98 UnknownArray>;
99
100/**
101Omit one path from the given object/array.
102*/
103type OmitDeepWithOnePath<T, Path extends string | number> =
104T extends NonRecursiveType
105 ? T
106 : T extends UnknownArray ? SetArrayAccess<OmitDeepArrayWithOnePath<T, Path>, IsArrayReadonly<T>>
107 : T extends object ? OmitDeepObjectWithOnePath<T, Path>
108 : T;
109
110/**
111Omit one path from the given object.
112*/
113type OmitDeepObjectWithOnePath<ObjectT extends object, P extends string | number> =
114P extends `${infer RecordKeyInPath}.${infer SubPath}`
115 ? {
116 [Key in keyof ObjectT]:
117 IsEqual<RecordKeyInPath, ToString<Key>> extends true
118 ? ExactKey<ObjectT, Key> extends infer RealKey
119 ? RealKey extends keyof ObjectT
120 ? OmitDeepWithOnePath<ObjectT[RealKey], SubPath>
121 : ObjectT[Key]
122 : ObjectT[Key]
123 : ObjectT[Key]
124 }
125 : ExactKey<ObjectT, P> extends infer Key
126 ? IsNever<Key> extends true
127 ? ObjectT
128 : Key extends PropertyKey
129 ? Omit<ObjectT, Key>
130 : ObjectT
131 : ObjectT;
132
133/**
134Omit one path from from the given array.
135
136It replaces the item to `unknown` at the given index.
137
138@example
139```
140type A = OmitDeepArrayWithOnePath<[10, 20, 30, 40], 2>;
141//=> type A = [10, 20, unknown, 40];
142```
143*/
144type OmitDeepArrayWithOnePath<ArrayType extends UnknownArray, P extends string | number> =
145 // Handle paths that are `${number}.${string}`
146 P extends `${infer ArrayIndex extends number}.${infer SubPath}`
147 // If `ArrayIndex` is equal to `number`
148 ? number extends ArrayIndex
149 ? Array<OmitDeepWithOnePath<NonNullable<ArrayType[number]>, SubPath>>
150 // If `ArrayIndex` is a number literal
151 : ArraySplice<ArrayType, ArrayIndex, 1, [OmitDeepWithOnePath<NonNullable<ArrayType[ArrayIndex]>, SubPath>]>
152 // If the path is equal to `number`
153 : P extends `${infer ArrayIndex extends number}`
154 // If `ArrayIndex` is `number`
155 ? number extends ArrayIndex
156 ? []
157 // If `ArrayIndex` is a number literal
158 : ArraySplice<ArrayType, ArrayIndex, 1, [unknown]>
159 : ArrayType;