1

Let's say we have that type:

type Product = {
  id: string;
  name: string;
  isActive: boolean;
  isAvailable: boolean;
}

Is it possible to dynamically create a new type from this one, but with keys as snake_case such as:

type ProductDb = {
  id: string;
  name: string;
  is_active: boolean;
  is_available: boolean;
}

If fact, I would like to define an Object <-> Database mapper that would be like:

class Mapper<Product, ProductDB> {
  ObjectToDb = (object: Product): ProductDb => {};
  DbToObject = (db: ProductDb): Product => {}
}

To go further it would be great to have a generic version of this mapper:

class Mapper<T, G> {
  ObjectToDb = (object: T): G => {};
  DbToObject = (db: G): T => {}
}
KValium
  • 111
  • 1
  • 11
  • 2
    Related: [TypeScript convert generic object from snake to camel case](https://stackoverflow.com/questions/60269936/typescript-convert-generic-object-from-snake-to-camel-case) – ford04 Jan 09 '21 at 13:07
  • It works great! Thanks ;) – KValium Jan 12 '21 at 07:49

1 Answers1

2

The comment link has the answer. If you're on TS 4.1+ you can do this:

type Product = {
    id: string;
    name: string;
    isActive: boolean;
    isAvailable: boolean;
};

type CamelToSnakeCase<S extends string> = string extends S
    ? string
    : S extends `${infer T}${infer U}`
    ? `${T extends Capitalize<T>
          ? '_'
          : ''}${Lowercase<T>}${CamelToSnakeCase<U>}`
    : S;

type ProductDb = { [K in keyof Product as CamelToSnakeCase<K>]: Product[K] };

The resulting type will look like this:

type ProductDb = {
    id: string;
    name: string;
    is_active: boolean;
    is_available: boolean;
}
Forrest
  • 1,370
  • 9
  • 20