Skip to the content.

Renaming properties in TypeScript

Using as in a mapped type, you can rename properties. For example, you can convert all properties to functions using this Lazy type.

type Lazy<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

The Person interface below will be converted to an interface with three functions.

interface Person {
  readonly name: string;
  readonly age: number;
  readonly location: string;
}

type LazyPerson = Lazy<Person>;

// This is equivalent to
// interface LazyPerson {
//   readonly getName: () => string;
//   readonly getAge: () => string;
//   readonly getLocation: () => string;
// }

Then, is it possible to do the opposite conversion? Yes, you can do it with this Strict type.

type Strict<T extends { [key: `get${string}`]: () => unknown }> = {
  [K in keyof T as K extends `get${infer UnK}` ? Uncapitalize<UnK> : never]: K extends `get${string}` ? ReturnType<T[K]>: never;
};

As you can see, it picks properties whose name matches getXxx and converts its name to xxx, then git it a return type of the original function.

You can get the original Person from LazyPerson with it.

type StrictPerson = Strict<LazyPerson>;

// This is equivalent to
// interface StrictPerson {
//   readonly name: string;
//   readonly age: number;
//   readonly location: string;
// }

As I wrote above, this Strict omits all properties whose name doesn’t match getXxx. So, for example, X won’t have y in the following example.

type X = Strict<{
  getX: () => string;
  y: number;
}>;

// This is equivalent to
// interface X {
//   x: string;
// }

You can preserve other properties using Strict2 below if you want.

type Strict2<T extends { [key: `get${string}`]: () => unknown }> = {
  [K in keyof T as K extends `get${infer UnK}` ? Uncapitalize<UnK> : K]: K extends `get${string}` ? ReturnType<T[K]>: T[K];
};
type X = Strict2<{
  getX: () => string;
  y: number;
}>;

// This is equivalent to
// interface X {
//   x: string;
//   y: number;
// }