Skip to the content.

Utility Types

There are utility types provided by typescript which are useful for common use cases

Partial

Allows to make all object properties “optional”

interface FullType {
  first: string;
  last: string;
}
const fullData: FullType = {
  first: "a",
  last: "b",
};
const partialData: Partial<FullType> = {
  last: "test",
};
console.log(partialData);

open code in online editor

Commonly used for partial data merge functions

interface FullUserMerge {
  first: string;
  last: string;
  email: string;
  gender: string;
}
const fullUser: FullUserMerge = {
  first: "a",
  last: "b",
  email: "test-email",
  gender: "f",
};
const mergeDataIntoUser = (
  user: FullUserMerge,
  partialData: Partial<FullUserMerge>
): FullUserMerge => ({
  ...user,
  ...partialData,
});

const mergedData1 = mergeDataIntoUser(fullUser, { gender: "f" });
const mergedData2 = mergeDataIntoUser(fullUser, {
  email: "some-email",
  last: "x",
});
console.log(mergedData1);
console.log(mergedData2);

open code in online editor

Required

Opposite of Partial, makes all properties required

interface MaybeSomeOptions {
  db?: string;
  apiUrl?: string;
  api: string; // this is not required, it will stay as is
}
type AllRequiredOptions = Required<MaybeSomeOptions>;
const allRequiredOptions: AllRequiredOptions = {
  db: "db-name", // required now
  apiUrl: "google.com", // required now
  api: "api-url", // required now
};
console.log(allRequiredOptions);

open code in online editor

Record

Allows to build an object type using 2 types: one for key and second for value

type FixedMap = Record<"a" | "b", number>;
const fixedTypeInstance: FixedMap = {
  a: 1,
  b: 2,
  // c: 3,// ... and 'c' does not exist in type
};

These 2 definitions are equal:

type ObjectWithStringKeys = { [key: string]: any };
type RecordWithStringKeys = Record<string, any>;

This type is very useful when object shape is not fully known.

Commonly used as a type for json parsing results, json should have keys as a string but contain many various “values”

const jsonData: Record<string, any> = JSON.parse(`{"nobody":"knows"}`);

Any type could be used to represent value

interface DynamoDbRecordType {
  userId: string;
  data: number;
}
const recordsByUserId: Record<string, DynamoDbRecordType> = {
  "1": {
    userId: "1",
    data: 100,
  },
  "2": {
    userId: "2",
    data: 200,
  },
};
console.log(recordsByUserId);

open code in online editor

Readonly

Set all properties of an object as readonly

interface DynamicInterface {
  a: string;
  b: number;
}
type ReadonlyInterface = Readonly<DynamicInterface>;
const readOnly: ReadonlyInterface = {
  a: "x",
  b: 1,
};
console.log(readOnly);

open code in online editor

readOnly.a = “xx”; // Cannot assign to ‘a’ because it is a read-only property.

Pick

Constructs new type by “picking” properties from another type.

In practice not so often used.

interface FullBigType {
  one: number;
  two: number;
  three: number;
  four: number;
  five: number;
}
type OneAndTwo = Pick<FullBigType, "one" | "two">;
const oneOrTwo: OneAndTwo = {
  one: 1,
  two: 2,
  // three  is not here
};
console.log(oneOrTwo);

open code in online editor

Omit

Removes some properties from type definition

interface DatabaseUserSecret {
  userId: string;
  login: string;
  password: string;
  name: string;
}
type DatabaseUserPublic = Omit<DatabaseUserSecret, "login" | "password">;
const privateDbUser: DatabaseUserSecret = {
  userId: "1",
  login: "username",
  password: "secret",
  name: "My Name",
};
const publicDbUser: DatabaseUserPublic = {
  userId: "1",
  name: "My Name",
  // login: "username", // ...and 'login' does not exist in type
  // password: "secret", // ...and 'password' does not exist in type
};
console.log(privateDbUser);
console.log(publicDbUser);

open code in online editor

This type is useful for a cases when type of some properties should be changed

interface DynamodbItemPlain {
  recordId: string;
  createdAt: string;
  updatedAt: string;
  data: string;
}

interface DynamodbItemData {
  userId: string;
  name: string;
}
interface DynamodbItemParsed extends Omit<DynamodbItemPlain, "data"> {
  data: DynamodbItemData;
}
const plainDbItem: DynamodbItemPlain = {
  recordId: "record-id",
  createdAt: "2020-01-01",
  updatedAt: "2020-02-02",
  data: `{"userId":"user-id", "name":"User Name"}`,
};
const convert = (origin: DynamodbItemPlain): DynamodbItemParsed => ({
  ...origin,
  data: JSON.parse(origin.data),
});
const parsedDbData = convert(plainDbItem);
console.log(parsedDbData); // this will have data as `DynamodbItemData`

open code in online editor

Other types

Check more utility types at official docs page

Exclude, Extract, NonNullable, ReturnType etc are not so often used