Utility types in TypeScript acts as helper types that allow us to model and create new types quickly.
NonNullable
Removes all the nullish types from a type declaration.
type MaybeString = string | null | undefined
type NonNullableString = NonNullable<MaybeString>
// is equivalent to
type NonNullableString = string
Object Types
Required and Partial
The Required
helper creates a new type that transform all fields of the underlying type as required, removing any optional markers (?
) exist within the type.
Partial
on the other hand generates a new type of identical fields but with the optional marker applied to all fields.
type User = {
id: string
name: string
age?: number
}
type RequiredUser = Required<User>
// equivalent to
type RequiredUser = {
id: string
name: string
age: number
}
type PartialUser = Partial<User>
// equivalent to
type PartialUser = {
id?: string
name?: string
age?: number
}
Omit and Pick
Omit
ignores the fields that is specified whereas Pick
only select the specified fields during the construction of the new type.
type User = {
id: string
name: string
age?: number
}
// Omitting one field
type OmittedUser = Omit<User, 'id'>
type OmittedUser = {
name: string
age?: number
}
// Omitting multiple fields
type OmittedUser2 = Omit<User, 'id' | 'name'>
type OmittedUser2 = {
age?: number
}
While you may argue picking a certain set of key from a type is as good as creating an entirely new type from scratch, there are certain benefits when it comes to Pick
. The most compelling reason to use Pick
is its readability.
Imagine there is type named User
as demonstrated but with whole lot more of fields. At the login page, you might need its id
and password
field and here is where Pick
comes in handy.
// Picking one property
type PickedUser = Pick<User, 'id'>
type PickedUser = {
id: string
}
// Picking multiple properties
type PickedUser2 = Pick<User, 'id' | 'name'>
type PickedUser2 = {
id: string
name: string
}
Record
Record
type allows us to specify the type for key and its value for an object (or dictionary).
type MyDictionary = Record<number, string>
// equivalent to
type MyDictionary = {
[key: number]: string
}
Readonly
Readonly
marks all the field for a type with readonly
keyword so that all the fields are immutable after creation.
type User = {
id: string
name: string
age?: number
}
type ReadonlyUser = Readonly<User>
type ReadonlyUser = {
readonly id: string
readonly name: string
readonly age?: number
}
Mutable
There are no Mutable
utility type in TypeScript that does the opposite of what Readonly
does, but we can create one ourselves easily.
type Mutable<T> = {
-readonly [K in keyof T]: T[K]
}
The -readonly
basically just removes the readonly keyword from a type while iterating through their key value pairs.
type MutableUser = Mutable<ReadonlyUser>
type MutableUser = {
id: string
name: string
age?: number
}
Union Type Helpers
Exclude
Exclude
does pretty much the same thing with Omit
, but with union types.
type Role = 'admin' | 'user' | 'anonymous'
type AnonymousRole = Exclude<Role, 'user' | 'admin'>
type AnonymousRole = 'anonymous'
Extract
Extract
is used to cherry pick a piece of type info present in a discriminated union with its key.
type RoleAttributes =
| { role: 'admin'; orgId: string }
| { role: 'user'; name: string }
| { role: 'anonymous' }
type UserRole = Extract<
RoleAttributes,
{
role: 'user'
}
>
Functions
These utility type are extremely useful when dealing with a library that does not have type sufficient declaration for its functions.
ReturnType
ReturnType
is pretty self-explanatory as it extracts the return type of a function itself.
type Func = (a: number, b: string) => string
type FuncReturnValue = ReturnType<Func>
type FuncReturnValue = string
Parameters
On the flipside, Parameters
extracts the parameters of a function type in the form of a named tuple (or array).
type FuncParams = Parameters<Func>
type FuncParams = [a: number, b: string]
To extract the parameters by position, simply index the individual by its index in the named tuple.
type FirstFuncParam = Parameters<Func>[0]
type FirstFuncParam = number
Promises
Promise
Defines an object of promise type.
type PromiseNumber = Promise<number>
Awaited
Awaited
on the other hand unwraps the underlying type of a Promise
type.
type Result = Awaited<PromiseNumber>
type Result = number