Skip to content

Instantly share code, notes, and snippets.

@lesleh
Created June 2, 2023 10:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lesleh/4a213c7cd312ec86729ab2bcd996d526 to your computer and use it in GitHub Desktop.
Save lesleh/4a213c7cd312ec86729ab2bcd996d526 to your computer and use it in GitHub Desktop.
TypeScript utilities to convert between cases
export type CamelCase<S extends string> =
S extends `${infer P1}_${infer P2}${infer P3}`
? `${Lowercase<P1>}${Uppercase<P2>}${CamelCase<P3>}`
: Lowercase<S>;
export type ObjectToCamel<T> = {
[K in keyof T as CamelCase<string & K>]: T[K] extends Record<string, any>
? KeysToCamelCase<T[K]>
: T[K];
};
export type KeysToCamelCase<T> = {
[K in keyof T as CamelCase<string & K>]: T[K] extends Array<any>
? KeysToCamelCase<T[K][number]>[]
: ObjectToCamel<T[K]>;
};
export function toCamelCase<T>(obj: T): KeysToCamelCase<T> {
const result = {} as KeysToCamelCase<T>;
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const camelCaseKey = key.replace(/_([a-z])/g, (_, letter) =>
letter.toUpperCase()
);
const value = obj[key];
if (Array.isArray(value)) {
// @ts-expect-error
result[camelCaseKey] = value.map(toCamelCase);
} else if (typeof value === "object" && value !== null) {
// @ts-expect-error
result[camelCaseKey] = toCamelCase(value);
} else {
// @ts-expect-error
result[camelCaseKey] = value;
}
}
}
return result;
}
export type SnakeCase<S extends string> = S extends `${infer P1}${infer P2}${infer P3}`
? `${P1 extends Lowercase<P1>
? ""
: "_"}${Lowercase<P1>}${SnakeCase<`${P2}${P3}`>}`
: S;
export type ObjectToSnake<T> = {
[K in keyof T as SnakeCase<string & K>]: T[K] extends Record<string, any>
? KeysToSnakeCase<T[K]>
: T[K];
};
export type KeysToSnakeCase<T> = {
[K in keyof T as SnakeCase<string & K>]: T[K] extends Array<any>
? KeysToSnakeCase<T[K][number]>[]
: ObjectToSnake<T[K]>;
};
export function toSnakeCase<T>(obj: T): KeysToSnakeCase<T> {
const result = {} as KeysToSnakeCase<T>;
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const snakeCaseKey = key.replace(
/[A-Z]/g,
(letter) => `_${letter.toLowerCase()}`
);
const value = obj[key];
if (Array.isArray(value)) {
// @ts-expect-error
result[snakeCaseKey] = value.map(toSnakeCase);
} else if (typeof value === "object" && value !== null) {
// @ts-expect-error
result[snakeCaseKey] = toSnakeCase(value);
} else {
// @ts-expect-error
result[snakeCaseKey] = value;
}
}
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment