Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A mapped type is a type expression that constructs a new object type by iterating over a union of property keys. It operates as a type-level comprehension, applying a specific transformation to each key and its associated value type to produce a derived object signature. Structurally, mapped types can only be declared using type aliases (type); attempting to define a mapped type within an interface declaration violates TypeScript syntax rules and will throw an error.

Base Syntax

The foundation of a mapped type relies on the in operator to iterate over a union of keys. These keys can be literal types, a union derived from an existing type, or the broad primitive types string, number, and symbol.
// Iterating over a literal union
type Flags = {
  [K in "a" | "b"]: boolean;
};

// Iterating over the keys of a generic type T
type Mapped<T> = {
  [K in keyof T]: T[K];
};

// Invalid: Cannot be declared via interface
// interface Flags { [K in "a" | "b"]: boolean; } // Syntax Error
  • K: A type variable representing the current key in the iteration.
  • in: The iteration operator that loops over the specified union of keys.
  • keyof T: The index type query operator that yields the union of known, public property names of T.
  • T[K]: The indexed access type, resolving to the type of the property K in the original type T.

Homomorphic Mapped Types and Modifier Preservation

When a mapped type iterates directly over the keys of an existing type using the keyof operator (e.g., [K in keyof T]), it is classified as a homomorphic mapped type. A critical characteristic of homomorphic mapped types is modifier preservation. By default, TypeScript automatically inherits and preserves the original readonly and optional (?) modifiers of the source type T in the resulting mapped type.
type Source = {
  readonly a: string;
  b?: number;
};

type Preserved<T> = {
  [K in keyof T]: T[K] | null;
};

// Preserved<Source> resolves to:
// { readonly a: string | null; b?: number | null; }

Mapping Modifiers

To override the default preservation behavior, mapped types can explicitly mutate the mutability (readonly) and optionality (?) of properties during the iteration process. These modifiers accept addition (+) or subtraction (-) prefixes to explicitly add or remove the mapping trait. If no prefix is provided, + is implicitly applied.
type MutableAndRequired<T> = {
  -readonly [K in keyof T]-?: T[K];
};

type ReadonlyAndOptional<T> = {
  +readonly [K in keyof T]+?: T[K];
};

Arrays and Tuples

Homomorphic mapped types exhibit specialized behavior when applied to array and tuple types. Instead of iterating over the array prototype properties (such as push, pop, or length), TypeScript maps strictly over the individual elements. This produces a new array or tuple type of the exact same length, applying the mapped transformation to the element types rather than returning a standard object type containing array methods as keys.
type Stringify<T> = {
  [K in keyof T]: string;
};

type Tuple = [number, boolean];
type StringifiedTuple = Stringify<Tuple>; 
// Resolves to: [string, string]
// Does NOT resolve to: { push: string; length: string; 0: string; 1: string; }

Key Remapping via as

TypeScript allows the transformation of the keys themselves during iteration using the as clause. This evaluates a template literal type or another type transformation to generate a new property key.
type RemappedKeys<T> = {
  [K in keyof T as `new_${string & K}`]: T[K];
};

Key Filtering

The as clause can also filter out properties during the mapping phase. If the as clause evaluates to the never type, that property is omitted entirely from the resulting mapped type.
type FilteredType<T, U> = {
  [K in keyof T as K extends U ? never : K]: T[K];
};

Iterating Over Broad Primitives

When a mapped type iterates over the broad primitive types string, number, or symbol rather than specific literal types, the resulting type expression generates an index signature instead of discrete properties.
type StringMap = {
  [K in string]: boolean; 
};
// Resolves to an index signature: { [x: string]: boolean; }
Master TypeScript with Deep Grasping Methodology!Learn More