Over the past few years of using Typescript and slowly getting comfortable writing complex custom types, I have amassed a collection of small helper types from around the internet. Here are a few of them that I end up adding to almost all my major projects and how I use them:

Unpromise

Sometimes you need to get the resolved value of a Promise<T> wrapped type, mostly when using along with the inbuilt ReturnType type:

type Unpromise<T> = T extends Promise<infer U> ? U : T;

type a = Promise<number>;
type x = Unpromise<a>; // number

Use with ReturnType to make ReturnTypeResolved:

type ReturnTypeResolved<T extends (...args: any) => any> = Unpromise<ReturnType<T>>;

function test(): Promise<{weird: 'value'}> {
  return Promise.resolve({weird: 'value'});
}

type WeirdType = ReturnTypeResolved<typeof test>;

Open in TS Playground

PlainObject

I know we have the inbuilt Record but this is such a common and frequent use case that I like having this around:

type PlainObject<T = any> = Record<string, T>;

type NumMap = PlainObject<number>;
const a: NumMap = {
  key1: 1,
  key2: 2,
  keyx: 'x', // ERROR: expected number
};

You can also create a reverse of this, ValueOf<T>:

type ValueOf<T> = T[keyof T];

type x = ValueOf<NumMap>; // number

Open in TS Playground

RecursivePartial

Partial but for nested objects, most useful when declaring defaults or merging some overrides for a config type:

type RecursivePartial<T> = {
  [P in keyof T]?:
    T[P] extends (infer U)[] ? RecursivePartial<U>[] :
    T[P] extends object ? RecursivePartial<T[P]> :
    T[P];
};

const config = {
  a: {
    x: {
      p: 1,
      q: 2,
    },
    y: 'nested',
    z: 'value',
  },
  b: 'root',
  c: 'value',
};

const configOverride: RecursivePartial<typeof config> = {
  a: {
    x: {
      p: 'wrong', // should be number
    },
  },
};

Open in TS Playground

Also See

Go over the inbuilt utility types in the Typescript Docs. And checkout this great library, utility-types on Github for other common types people tend to use.

Credits

Links to the various places I originally found these from: