Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript generic to turn underscore object to camel case

Tags:

typescript

Let's say I have an interface like this

interface Example {
    first_name: string,
    last_name: string,
    home_town: string,
}

I am looking for a generic like Camelize that can take Example and switch all the keys to be valid if they are camelized instead of underscore.

const e: Camelize<Example> = {
  firstName: 'string',
  lastName: 'string',
  homeTown: 'string'
}

Is this possible?

like image 775
ThomasReggi Avatar asked Dec 06 '22 09:12

ThomasReggi


1 Answers

UPDATE for TypeScript 4.5:

With the introduction of tail recursion elimination on conditional types, it is now possible to write a version of Camelize that converts keys to camel case without running into recursion depth limits as easily as before:

The CamelizeString<T, C> type uses C as an accumulator to store intermediate results of turning the snake case string in T to the camel case string in C.

type CamelizeString<T extends PropertyKey, C extends string = ""> =
    T extends string ? string extends T ? string :
    T extends `${infer F}_${infer R}` ?
    CamelizeString<Capitalize<R>, `${C}${F}`> : `${C}${T}` : T;

The rest of the code is the same as the version below.

Playground link to code


TypeScript 4.1 introduced template literal types and key remapping in mapped types (see microsoft/TypeScript#40336), so you can achieve it this way:

type CamelizeString<T extends PropertyKey> = 
    T extends string ? string extends T ? string :
    T extends `${infer F}_${infer R}` ? `${F}${Capitalize<CamelizeString<R>>}` : T : T;

type Camelize<T> = { [K in keyof T as CamelizeString<K>]: T[K] }

type CamelizeExample = Camelize<Example>;
/* type CamelizeExample = {
    firstName: string;
    lastName: string;
    homeTown: string;
} */

const e: Camelize<Example> = {
    firstName: 'string',
    lastName: 'string',
    homeTown: 'string'
}

The implementation of CamelizeString<T> finds the first underscore character ("_") in a string T, removes it, and capitalizes the remainder of the string after recursively calling CamelizeString on that remainder. And Camelize<T> remaps each key K of T to CamelizeString<K>.

Playground link to code

like image 187
jcalz Avatar answered Dec 08 '22 00:12

jcalz