Learn TypeScript - Advanced Mapped Types and Conditional Types
Episode 12 of 23

Learn TypeScript - Advanced Mapped Types and Conditional Types

This episode unlocks type transformation: mapped types for creating types from other types, key remapping with as, conditional types with extends and infer, and the built-in utility types built from both.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

So far you've built types from scratch. Episode 12 changes how you think: types can be generated from other types. With type operations, one source definition can spawn optional variants, readonly variants, selected properties, or shapes that depend on conditions.

This power comes from two families: mapped types, which iterate over properties to form new types, and conditional types, which choose a type based on a condition. Built-in utility types like Partial and Omit are just combinations of the two.

Episode 12 dissects both from concept to infer patterns, then closes with the most-used utility types. You'll read library types that look complex with understanding, not guesswork.

keyof and Mapped Types

Iterating over Properties

A mapped type iterates over every property key of the source type:

Mapped type sederhana
type Opsional<T> = {
    [K in keyof T]?: T[K];
};
 
interface Pengguna {
    nama: string;
    umur: number;
}
 
type PenggunaOpsional = Opsional<Pengguna>;

The declaration [K in keyof T] iterates over T's keys, then T[K] takes the type of that key. Opsional<Pengguna> produces a shape with every property marked optional. The result is equivalent to Partial<Pengguna>, covered below.

Adding Modifiers

Mapped types can also add or remove modifiers:

Membuat readonly
type Terkunci<T> = {
    readonly [K in keyof T]: T[K];
};
 
const data: Terkunci<Pengguna> = { nama: "Andi", umur: 25 };
data.nama = "Budi";

The readonly marker on the result maps every property to readonly. The readonly and optional modifiers can be removed with a minus prefix, for example -readonly and -?. Mapped types give you full control over the output shape.

Key Remapping with as

The keys of a mapping result can be changed using the as keyword:

Key remapping
type Prefiks<K extends string> = {
    [P in K as `get${Capitalize<P>}`]: () => string;
};
 
type Akses = Prefiks<"nama" | "umur">;

Mapping with the as keyword renames keys into getter shapes, for example getNama. Key remapping is the foundation of utilities like Omit and many validation libraries. Template expressions at the type level open up enormous expressive space.

Conditional Types

T extends U ? X : Y

A conditional type chooses a type based on compatibility:

Conditional type dasar
type TipeParam<T> = T extends string ? "teks" : "lainnya";
 
type A = TipeParam<string>;
type B = TipeParam<number>;

TipeParam<string> evaluates to "teks" because string satisfies T extends string. TipeParam<number> falls into the "lainnya" branch. A conditional type works like a ternary at the type level and is the foundation of many advanced patterns.

Distribution and infer

A conditional type distributes automatically over union members, and infer captures a type from inside a structure:

infer dalam conditional type
type Elemen<T> = T extends (infer U)[] ? U : never;
 
type Nomor = Elemen<number[]>;
type StringAta = Elemen<string[]>;
 
type Terlepas<T> = T extends Promise<infer U> ? U : T;
type Hasil = Terlepas<Promise<number>>;

infer U captures the array element type or the value inside a Promise. Terlepas<Promise<number>> evaluates to number, while Terlepas<string> stays string. Utilities like Awaited and ReturnType are built from this infer pattern.

Utility Types from Mapped and Conditional

TypeScript ships ready-to-use utilities:

Utility types umum
interface Pesanan {
    id: number;
    nama: string;
    jumlah: number;
}
 
type Sebagian = Partial<Pesanan>;
type Dipilih = Pick<Pesanan, "id" | "nama">;
type Dibuang = Omit<Pesanan, "jumlah">;
type Petakan = Record<string, number>;

Partial makes every property optional, Pick takes a subset of properties, Omit drops properties, and Record builds an object with a uniform key-value pattern. These four are the most frequently used utilities, and all of them come from mapped types.

Info

Utility types are neatly wrapped patterns. You don't need to rewrite them. But understanding how they work matters so you can create custom variants that aren't available in the library.

Closing

Episode 12 gives you advanced capability: mapped types change the shape of types, conditional types choose based on conditions, and infer captures hidden types. With these, built-in utility types are no longer a black box.

Key takeaways:

  • A mapped type iterates over properties with [K in keyof T].
  • The readonly and optional modifiers can be added or removed.
  • Key remapping with as renames the keys of a mapping result.
  • A conditional type T extends U ? X : Y chooses a type based on a condition.
  • infer captures a type from inside structures like Promise and arrays.
  • Partial, Pick, Omit, and Record are the most frequently used utilities.

In the next episode 13 we'll discuss migrating JavaScript code to TypeScript — a gradual strategy for securing an existing codebase without rewriting everything at once.

Learn TypeScript - Advanced Mapped Types and Conditional Types | Learn TypeScript