-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathindex.d.ts
120 lines (108 loc) · 3.33 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
import { SnakeCase } from "type-fest";
import { Options as SnakeCaseOptions } from "snake-case";
// eslint-disable-next-line @typescript-eslint/ban-types
type EmptyTuple = [];
// Allow union with, for example, `undefined` and `null`.
type ObjectUnion = Record<string, unknown> | unknown;
/**
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;
/**
Check if an element is included in a tuple.
@template List - List of values.
@template Target - Target to search.
*/
type Includes<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
: Includes<Rest, Target>
: boolean;
/**
Append a segment to dot-notation path.
@template S - Base path.
@template Last - Additional path.
*/
type AppendPath<S extends string, Last extends string> = S extends ""
? Last
: `${S}.${Last}`;
declare namespace snakecaseKeys {
/**
Convert keys of an object to snake-case strings.
@template T - Input object or array.
@template Deep - Deep conversion flag.
@template Exclude - Excluded keys.
@template Path - Path of keys.
*/
export type SnakeCaseKeys<
T extends ObjectUnion | ReadonlyArray<Record<string, unknown>>,
Deep extends boolean = true,
Exclude extends readonly unknown[] = EmptyTuple,
Path extends string = ""
> = T extends ReadonlyArray<Record<string, unknown>>
? // Handle arrays or tuples.
{
[P in keyof T]: T[P] extends Record<string, unknown> | ReadonlyArray<Record<string, unknown>>
? SnakeCaseKeys<T[P], Deep, Exclude>
: T[P];
}
: T extends Record<string, unknown>
? // Handle objects.
{
[P in keyof T as [Includes<Exclude, P>] extends [true]
? P
: SnakeCase<P>]: [Deep] extends [true]
? T[P] extends ObjectUnion | ReadonlyArray<Record<string, unknown>>
? SnakeCaseKeys<T[P], Deep, Exclude, AppendPath<Path, P & string>>
: T[P]
: T[P];
}
: // Return anything else as-is.
T;
interface Options {
/**
Recurse nested objects and objects in arrays.
@default true
*/
readonly deep?: boolean;
/**
Exclude keys from being snakeCased.
@default []
*/
readonly exclude?: ReadonlyArray<string | RegExp>;
/**
A function that determines whether to recurse for a specific key and value.
*/
readonly shouldRecurse?: {
(key: any, value: any): boolean;
}
/**
Options object that gets passed to snake-case parsing function.
@default {}
*/
readonly parsingOptions?: SnakeCaseOptions;
}
}
/**
Convert object keys to snake using [`to-snake-case`](https://github.com/ianstormtaylor/to-snake-case).
@param input - Object or array of objects to snake-case.
@param options - Options of conversion.
*/
declare function snakecaseKeys<
T extends Record<string, unknown> | ReadonlyArray<Record<string, unknown>>,
Options extends snakecaseKeys.Options
>(
input: T,
options?: Options
): snakecaseKeys.SnakeCaseKeys<
T,
Options["deep"] extends boolean ? Options["deep"] : true,
WithDefault<Options["exclude"], EmptyTuple>
>;
export = snakecaseKeys;