1import { snakeCase } from "case-anything";
2
3// https://stackoverflow.com/questions/60269936/typescript-convert-generic-object-from-snake-to-camel-case
4
5// Typescript magic to convert any string from camelCase to snake_case at compile time
6type SnakeCase<S> =
7 S extends string ?
8 S extends `${infer T}${infer U}` ?
9 `${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${SnakeCase<U>}` :
10 S :
11 S;
12
13type SnakeCased<Type> = {
14 [Property in keyof Type as SnakeCase<Property>]: SnakeCased<Type[Property]>
15}
16
17export default function snakeCaseTree<T>(object: T): SnakeCased<T> {
18 const snakeObject: any = {};
19 for (const key in object) {
20 snakeObject[snakeCase(key)] = snakeCaseValue(object[key]);
21 }
22 return snakeObject;
23}
24
25function snakeCaseValue(value: any): any {
26 if (typeof value === "object") {
27 if (Array.isArray(value)) {
28 return value.map(snakeCaseValue);
29 } else {
30 return snakeCaseTree(value);
31 }
32 } else {
33 return value;
34 }
35}