TypeScriptGenerics and advanced types
Mapped types
Create a new object type by transforming every key of another type.
Example
#TypeScript
type Nullable<T> = { [K in keyof T]: T[K] | null }
type Flags<T> = { [K in keyof T]: boolean }
interface Profile {
name: string
bio: string
avatar: string
}
const draft: Nullable<Profile> = { name: 'Emma', bio: null, avatar: null }
const filled: Flags<Profile> = { name: true, bio: false, avatar: false }
const done = Object.values(filled).filter(Boolean).length
console.log(draft.name, `${done}/3 fields`)Result
Emma 1/3 fields
Definition and usage
#A mapped type iterates over the keys of a type and creates a new field for each one: { [K in keyof T]: T[K] | null } turns every field of T into a field that can also be null.
While mapping, you can add and remove modifiers: you add readonly and ?, and remove them with -readonly and -?. That’s how Partial, Required, and Readonly are built.
Since TypeScript 4.1, you can also rename keys with as, for example turning fields into getter names: [K in keyof T as `get${Capitalize<K & string>}`].
Syntax
#Syntax
type New<T> = { [K in keyof T]: NewFieldType }More examples
#TypeScript
type Getters<T> = {
[K in keyof T as `get${Capitalize<K & string>}`]: () => T[K]
}
type LevelGetters = Getters<{ level: number; name: string }>
// type LevelGetters = { getLevel: () => number; getName: () => string }Good practices
#- Before writing your own mapped type, check the built-in
Partial,Required,Readonly,Record, andPick. - The
-?and-readonlymodifiers let you remove optionality and read-only status.
Related entries
#- keyofCreates a union of the key names of a given object type.
- Partial<Type>Creates a type where every property is optional.
- Readonly<Type>Creates a type where every property is read-only.
- Template literal typesString types built from templates, like `${A}-${B}`.
- Record<Keys, Type>Creates an object type with given keys, where every value has the same type.
Spotted a mistake or missing an example? Write to us.