UNPKG

3.72 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// Supports array
42type A = OmitDeep<[1, 'foo', 2], 1>;
43// type A = [1, unknown, 2];
44
45// Supports recursing into array
46
47type Info1 = {
48 address: [
49 {
50 street: string
51 },
52 {
53 street2: string,
54 foo: string
55 };
56 ];
57}
58type AddressInfo = OmitDeep<Info1, 'address.1.foo'>;
59// type AddressInfo = {
60// address: [
61// {
62// street: string;
63// },
64// {
65// street2: string;
66// };
67// ];
68// };
69```
70
71@category Object
72@category Array
73*/
74export type OmitDeep<T, PathUnion extends LiteralUnion<Paths<T>, string>> =
75 SimplifyDeep<
76 SharedUnionFieldsDeep<
77 {[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion]
78 >,
79 UnknownArray>;
80
81/**
82Omit one path from the given object/array.
83*/
84type OmitDeepWithOnePath<T, Path extends string | number> =
85T extends NonRecursiveType
86 ? T
87 : T extends UnknownArray ? SetArrayAccess<OmitDeepArrayWithOnePath<T, Path>, IsArrayReadonly<T>>
88 : T extends object ? OmitDeepObjectWithOnePath<T, Path>
89 : T;
90
91/**
92Omit one path from the given object.
93*/
94type OmitDeepObjectWithOnePath<ObjectT extends object, P extends string | number> =
95P extends `${infer RecordKeyInPath}.${infer SubPath}`
96 ? {
97 [Key in keyof ObjectT]:
98 IsEqual<RecordKeyInPath, ToString<Key>> extends true
99 ? ExactKey<ObjectT, Key> extends infer RealKey
100 ? RealKey extends keyof ObjectT
101 ? OmitDeepWithOnePath<ObjectT[RealKey], SubPath>
102 : ObjectT[Key]
103 : ObjectT[Key]
104 : ObjectT[Key]
105 }
106 : ExactKey<ObjectT, P> extends infer Key
107 ? IsNever<Key> extends true
108 ? ObjectT
109 : Key extends PropertyKey
110 ? Omit<ObjectT, Key>
111 : ObjectT
112 : ObjectT;
113
114/**
115Omit one path from from the given array.
116
117It replaces the item to `unknown` at the given index.
118
119@example
120```
121type A = OmitDeepArrayWithOnePath<[10, 20, 30, 40], 2>;
122//=> type A = [10, 20, unknown, 40];
123```
124*/
125type OmitDeepArrayWithOnePath<ArrayType extends UnknownArray, P extends string | number> =
126 // Handle paths that are `${number}.${string}`
127 P extends `${infer ArrayIndex extends number}.${infer SubPath}`
128 // If `ArrayIndex` is equal to `number`
129 ? number extends ArrayIndex
130 ? Array<OmitDeepWithOnePath<NonNullable<ArrayType[number]>, SubPath>>
131 // If `ArrayIndex` is a number literal
132 : ArraySplice<ArrayType, ArrayIndex, 1, [OmitDeepWithOnePath<NonNullable<ArrayType[ArrayIndex]>, SubPath>]>
133 // If the path is equal to `number`
134 : P extends `${infer ArrayIndex extends number}`
135 // If `ArrayIndex` is `number`
136 ? number extends ArrayIndex
137 ? []
138 // If `ArrayIndex` is a number literal
139 : ArraySplice<ArrayType, ArrayIndex, 1, [unknown]>
140 : ArrayType;