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> = S extends string
7 ? S extends `${infer T}${infer U}`
8 ? `${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${SnakeCase<U>}`
9 : S
10 : S
11
12type SnakeCased<Type> = {
13 [Property in keyof Type as SnakeCase<Property>]: SnakeCased<Type[Property]>
14}
15
16export default function snakeCaseTree<T>(object: T): SnakeCased<T> {
17 const snakeObject: any = {}
18 for (const key in object) {
19 snakeObject[snakeCase(key, { keepSpecialCharacters: true })] =
20 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}