Mapped Types
11 min read
Mapped Types
A mapped type iterates over the keys of another type and produces a new object type by transforming each property. The syntax uses in keyof inside the type-level {} braces.
ts
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
type Optional<T> = {
[K in keyof T]?: T[K];
};
type Nullable<T> = {
[K in keyof T]: T[K] | null;
};
interface User {
id: number;
name: string;
email: string;
}
type NullableUser = Nullable<User>;
// { id: number | null; name: string | null; email: string | null }Remapping keys with `as`
TypeScript 4.1 introduced key remapping via as. You can rename keys in the output type using template literal types.
ts
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<User>;
// { getId: () => number; getName: () => string; getEmail: () => string }
// Filter out keys by remapping to never
type OmitFunctions<T> = {
[K in keyof T as T[K] extends Function ? never : K]: T[K];
};The built-in utility types Partial, Required, Readonly, and Record are all implemented as mapped types under the hood. Writing your own mapped types is the key skill for building reusable type-level abstractions.
Ready to test yourself?
Practice TypeScript— quiz & coding exercises