typescript

Typescript how to map type keys to camelCase


I'm new to typescript but I want to create a mapped type that converts keys from another type. Specifically, say I have a type where all the keys are snake-cased, how can I create a type where they are all camel-cased?

I thought I could do something like

type CamelCase<T> = {
  [_.camelCase(P in keyof T)]: T[P];
}

type MyCamelCaseType = CamelCase<SnakeCaseType>;

But TS doesn't like this. How can I transform the keys of an existing type to create a new type in this way?


Solution

  • In Typescript 4.1, template literal types got quite an upgrade. This is a problem I have wanting to be solved for a while and with a bit of tweaking managed to come up with this:

    type CamelCase<S extends string> = S extends `${infer P1}_${infer P2}${infer P3}`
      ? `${Lowercase<P1>}${Uppercase<P2>}${CamelCase<P3>}`
      : Lowercase<S>
    
    type KeysToCamelCase<T> = {
        [K in keyof T as CamelCase<string &K>]: T[K] extends {} ? KeysToCamelCase<T[K]> : T[K]
    }
    
    
    interface SnakeCase {
        bar_value: string;
        baz_value: {
            blah_test: number;
        }
    }
    
    const transformed: KeysToCamelCase<SnakeCase> = {
        bazValue: {
            blahTest: 2
        },
        barValue: 'test'
    }
    

    I can recommend reading: https://dev.to/phenomnominal/i-need-to-learn-about-typescript-template-literal-types-51po and also trying some of these Typescript challenges https://github.com/type-challenges/type-challenges to learn more about these literal types.