Home/Learn/JavaScript & TypeScript/Advanced Types — Mapped, Conditional and Template Literal

Advanced Types — Mapped, Conditional and Template Literal

Advanced
TypeScript

The type system is itself a small functional language. You will read far more of this than you write, and knowing the syntax is what makes library types comprehensible.

Overview

Mapped types transform every key of a type, conditional types branch on a type, and template literal types build string types from other types. Together they are how the utility types are implemented and how libraries express things like "the keys of this object whose values are functions". The honest guidance is to reach for these sparingly in application code — a type nobody on the team can read is a liability — but to be able to read them, because every serious library's type definitions use them.

Mapped Types

Iterate over keys and transform. This is how Partial and Readonly are defined.

Transforming every key of a type
type Partial<T> = { [K in keyof T]?: T[K] }
type Readonly<T> = { readonly [K in keyof T]: T[K] }
type Nullable<T> = { [K in keyof T]: T[K] | null }

// Removing modifiers with minus
type Mutable<T> = { -readonly [K in keyof T]: T[K] }
type Concrete<T> = { [K in keyof T]-?: T[K] }

// Remapping keys with 'as'
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}
type UserGetters = Getters<{ name: string; age: number }>
// { getName: () => string; getAge: () => number }

// Filtering keys — map to never to drop them
type OnlyStrings<T> = {
  [K in keyof T as T[K] extends string ? K : never]: T[K]
}

Conditional Types and infer

A ternary for types. infer pulls a type out of a position.

extends ? : and infer
type IsArray<T> = T extends any[] ? true : false

// infer captures whatever is in that slot
type Unwrap<T> = T extends Promise<infer U> ? U : T
type A = Unwrap<Promise<string>>       // string
type B = Unwrap<number>                // number

type ElementOf<T> = T extends (infer E)[] ? E : never
type C = ElementOf<Problem[]>          // Problem

// This is how ReturnType is written:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never

// Distribution: a conditional over a union applies to each member
type NoNull<T> = T extends null | undefined ? never : T
type D = NoNull<string | null>         // string
// Wrap in [] to stop distributing:
type NoDistribute<T> = [T] extends [null] ? true : false

Template Literal Types

String types built from other types. Route paths and event names are the practical uses.

Building string types
type Level = 'easy' | 'hard'
type Track = 'dsa' | 'java'

type Path = `/learn/${Track}`               // '/learn/dsa' | '/learn/java'
type Combo = `${Track}-${Level}`            // 4 combinations, all checked

type EventName<T extends string> = `on${Capitalize<T>}`
type E = EventName<'click'>                  // 'onClick'

// Built-in string manipulators
Uppercase<'abc'>     // 'ABC'
Lowercase<'ABC'>     // 'abc'
Capitalize<'abc'>    // 'Abc'
Uncapitalize<'Abc'>  // 'abc'

// Practical: typed route params
type Params<P extends string> =
  P extends `${string}:${infer K}/${infer Rest}` ? K | Params<Rest>
  : P extends `${string}:${infer K}` ? K
  : never
type R = Params<'/problems/:slug/:tab'>      // 'slug' | 'tab'

// Restraint applies. If a teammate cannot read the type, the
// safety it buys is smaller than the time it costs.

Key Points to Remember

  • 1Mapped types iterate over keyof T and transform each key; -readonly and -? remove modifiers
  • 2`as` inside a mapped type remaps key names, and mapping a key to never removes it
  • 3Conditional types are ternaries over types; infer captures a type from a position
  • 4A conditional type distributes over a union unless you wrap both sides in a tuple
  • 5Template literal types build string unions — useful for routes and event names, but keep them readable

Interview Questions

Sign in to ask Aria
1

How is Partial<T> implemented in TypeScript?

Medium
2

What does `infer` do in a conditional type?

Hard
3

What does it mean that conditional types distribute over unions, and how do you prevent it?

Hard

Ask Aria about Advanced Types — Mapped, Conditional and Template Literal

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…