-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.d.ts
148 lines (125 loc) · 3.38 KB
/
index.d.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import type {DelimiterCase} from 'type-fest';
// eslint-disable-next-line @typescript-eslint/ban-types
type EmptyTuple = [];
/**
Return a default type if input type is nil.
@template T - Input type.
@template U - Default type.
*/
type WithDefault<T, U extends T> = T extends undefined | void | null ? U : T; // eslint-disable-line @typescript-eslint/ban-types
// TODO: Replace this with https://github.com/sindresorhus/type-fest/blob/main/source/includes.d.ts
/**
Check if an element is included in a tuple.
*/
type IsInclude<List extends readonly unknown[], Target> = List extends undefined
? false
: List extends Readonly<EmptyTuple>
? false
: List extends readonly [infer First, ...infer Rest]
? First extends Target
? true
: IsInclude<Rest, Target>
: boolean;
/**
Convert the keys of an object from camel case.
*/
export type DecamelizeKeys<
T extends Record<string, any> | readonly any[],
Separator extends string = '_',
Exclude extends readonly unknown[] = EmptyTuple,
Deep extends boolean = false,
> = T extends readonly any[]
// Handle arrays or tuples.
? {
[P in keyof T]: T[P] extends Record<string, any> | readonly any[]
// eslint-disable-next-line @typescript-eslint/ban-types
? {} extends DecamelizeKeys<T[P], Separator>
? T[P]
: DecamelizeKeys<
T[P],
Separator,
Exclude,
Deep
>
: T[P];
}
: T extends Record<string, any>
// Handle objects.
? {
[
P in keyof T as [IsInclude<Exclude, P>] extends [true]
? P
: DelimiterCase<P, Separator>
]: Record<string, unknown> extends DecamelizeKeys<T[P]>
? T[P]
: [Deep] extends [true]
? DecamelizeKeys<
T[P],
Separator,
Exclude,
Deep
>
: T[P];
}
// Return anything else as-is.
: T;
type Options<Separator> = {
/**
The character or string used to separate words.
Important: You must use `as const` on the value.
@default '_'
@example
```
import decamelizeKeys from 'decamelize-keys';
decamelizeKeys({fooBar: true});
//=> {foo_bar: true}
decamelizeKeys({fooBar: true}, {separator: '-' as const});
//=> {'foo-bar': true}
```
*/
readonly separator?: Separator;
/**
Exclude keys from being camel-cased.
If this option can be statically determined, it's recommended to add `as const` to it.
@default []
*/
readonly exclude?: ReadonlyArray<string | RegExp>;
/**
Recurse nested objects and objects in arrays.
@default false
@example
```
import decamelizeKeys from 'decamelize-keys';
decamelizeKeys({fooBar: true, nested: {unicornRainbow: true}}, {deep: true});
//=> {foo_bar: true, nested: {unicorn_rainbow: true}}
```
*/
readonly deep?: boolean;
};
/**
Convert object keys from camel case using [`decamelize`](https://github.com/sindresorhus/decamelize).
@param input - Object or array of objects to decamelize.
@example
```
import decamelizeKeys from 'decamelize-keys';
// Convert an object
decamelizeKeys({fooBar: true});
//=> {foo_bar: true}
// Convert an array of objects
decamelizeKeys([{fooBar: true}, {barFoo: false}]);
//=> [{foo_bar: true}, {bar_foo: false}]
```
*/
export default function decamelizeKeys<
T extends Record<string, any> | readonly any[],
Separator extends string = '_',
OptionsType extends Options<Separator> = Options<Separator>,
>(
input: T,
options?: Options<Separator>
): DecamelizeKeys<
T,
Separator,
WithDefault<OptionsType['exclude'], EmptyTuple>,
WithDefault<OptionsType['deep'], false>
>;