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.

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.
A mapped type iterates over every property key of the source type:
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.
Mapped types can also add or remove modifiers:
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.
The keys of a mapping result can be changed using the as keyword:
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.
A conditional type chooses a type based on compatibility:
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.
A conditional type distributes automatically over union members, and infer captures a type from inside a structure:
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.
TypeScript ships ready-to-use utilities:
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.
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:
[K in keyof T].readonly and optional modifiers can be added or removed.as renames the keys of a mapping result.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.