M Logo
๐Ÿ“ TypeScript from Zero ยท Part 41 of 50

TypeScript Mapped Types: [K in keyof T], readonly and Key Remapping with as

November 6, 2026

Welcome to episode 41 of TypeScript from Zero, a series for complete beginners (no JavaScript needed). Welcome back to TypeScript from zero! In episode thirty two we used Partial and Readonly. But how are they made? With a mapped type: a loop over the keys of a type. Today we write our own. A new file called mapped.ts in the tasks project. Every code block below is the exact code and output from the video, ready to copy.

Setup

We start in the terminal and open the project in VS Code:

bash
cd tasks
touch src/mapped.ts
code .

1. Mapped type

The syntax looks like an object with one special key. Square brackets, K in key of T, means: for every key K of T. The value is T indexed by K, the same type as before. With a question mark after the brackets, every property becomes optional. This is exactly how Partial works. So an object with only dark is fine.

src/mapped.ts:

ts
type Flags = { dark: boolean; compact: boolean };
type Optional<T> = { [K in keyof T]?: T[K] };
const some: Optional<Flags> = { dark: true };
console.log(some);
text
$ node src/mapped.ts
{ dark: true }

2. Modifiers

We can change the modifiers. With the word readonly before the brackets, every property is read only. Assigning to one of them is an error: cannot assign to dark, because it is a read only property. TS2540.

src/mapped.ts:

ts
type Flags = { dark: boolean; compact: boolean };
type Optional<T> = { [K in keyof T]?: T[K] };
const some: Optional<Flags> = { dark: true };
console.log(some);
type Frozen<T> = { readonly [K in keyof T]: T[K] };
const fixed: Frozen<Flags> = { dark: true, compact: false };
fixed.dark = false;
text
$ npx tsc --noEmit
src/mapped.ts:7:7 - error TS2540: Cannot assign to 'dark' because it is a read-only property.

7 fixed.dark = false;
        ~~~~

Found 1 error in src/mapped.ts:7

3. Fix

We delete the assignment.

src/mapped.ts:

ts
type Flags = { dark: boolean; compact: boolean };
type Optional<T> = { [K in keyof T]?: T[K] };
const some: Optional<Flags> = { dark: true };
console.log(some);
type Frozen<T> = { readonly [K in keyof T]: T[K] };
const fixed: Frozen<Flags> = { dark: true, compact: false };
bash
$ npx tsc --noEmit

4. Remapping

A mapped type can also rename the keys, with the word as. Here every key becomes get plus the name with a capital letter, using a template literal type and Capitalize. And every value becomes a function that returns the old value type. So dark turns into get dark, a function that returns a boolean. But the object that we wrote has only get dark. tsc says: property get compact is missing. TS2741.

src/mapped.ts:

ts
type Flags = { dark: boolean; compact: boolean };
type Optional<T> = { [K in keyof T]?: T[K] };
const some: Optional<Flags> = { dark: true };
console.log(some);
type Frozen<T> = { readonly [K in keyof T]: T[K] };
const fixed: Frozen<Flags> = { dark: true, compact: false };
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
const g: Getters<Flags> = { getDark: () => true };
console.log(g.getDark());
text
$ npx tsc --noEmit
src/mapped.ts:10:7 - error TS2741: Property 'getCompact' is missing in type '{ getDark: () => true; }' but required in type 'Getters<Flags>'.

10 const g: Getters<Flags> = { getDark: () => true };
         ~

Found 1 error in src/mapped.ts:10

5. Fix

We add the missing function, and the program runs.

src/mapped.ts:

ts
type Flags = { dark: boolean; compact: boolean };
type Optional<T> = { [K in keyof T]?: T[K] };
const some: Optional<Flags> = { dark: true };
console.log(some);
type Frozen<T> = { readonly [K in keyof T]: T[K] };
const fixed: Frozen<Flags> = { dark: true, compact: false };
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
const g: Getters<Flags> = { getDark: () => true, getCompact: () => false };
console.log(g.getDark());
text
$ node src/mapped.ts
{ dark: true }
true
bash
$ npx tsc --noEmit

Recap

Today: mapped types with K in key of T, the question mark and readonly modifiers, and renaming keys with as. Next episode: conditional types and infer.

ยฉ 2026 All Rights Reserved By Mahmudul Alam