0Pricing
TypeScript Academy · Lesson

Index Signatures vs Record

Choose between index signatures and the Record utility type.

Index Signatures vs Record is a free TypeScript Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Two Ways to Type a Map

TypeScript offers two common ways to describe a dictionary: an index signature like { [k: string]: V }, and the built-in utility type Record<K, V>. They overlap heavily but read differently.

The Record Utility Type

Record<K, V> constructs an object type whose keys are K and whose values are V. With string as the key, it is equivalent to a string index signature.

type Scores = Record<string, number>
const game: Scores = { alice: 10, bob: 7 }
console.log(game.alice)

Equivalent to an Index Signature

These two types describe the same shape. Record<string, number> and { [key: string]: number } are interchangeable for arbitrary string keys.

type A = Record<string, number>
type B = { [key: string]: number }
const a: A = { x: 1 }
const b: B = a // assignable both ways
console.log(b.x)

Record With a Literal Key Union

The real power of Record appears with a finite union of literal keys. It produces an object where every listed key is required — something an index signature cannot express.

type Role = "admin" | "editor" | "viewer"
type Perms = Record<Role, boolean>
const p: Perms = { admin: true, editor: true, viewer: false }
console.log(p.admin)

Missing Keys Are Caught

Because each literal key is required, forgetting one is a compile error. This is a strong guarantee that index signatures simply cannot provide.

type Role = "admin" | "editor" | "viewer"
// const bad: Record<Role, boolean> = { admin: true, editor: true }
// Error: property viewer is missing

Index Signature Allows Any Key

By contrast, an index signature is open-ended. You can add keys never mentioned anywhere, and nothing is required to be present.

type Open = { [key: string]: number }
const o: Open = {}      // no keys required
o.anything = 1          // any key allowed
console.log(o.anything)

Finite Key Sets: Prefer Record

When the keys are a known, finite set, Record with a literal union is clearer and safer. It documents exactly which keys exist and enforces completeness.

type Direction = "north" | "south" | "east" | "west"
type Moves = Record<Direction, number>
const m: Moves = { north: 1, south: 0, east: 2, west: 0 }
console.log(m.east)

Open Key Sets: Either Works

When keys are unbounded and discovered at runtime, both Record<string, V> and an index signature work. Many teams pick Record for brevity, others pick the signature for explicitness.

type Cache1 = Record<string, string>
type Cache2 = { [url: string]: string }
const c: Cache1 = {}
c["/home"] = "<html>"
console.log(c["/home"])

Record Is Just a Mapped Type

Under the hood Record<K, V> is defined as a mapped type: { [P in K]: V }. Knowing this explains why a literal union yields required keys while string yields an index signature.

// lib definition (simplified):
// type Record<K extends string | number | symbol, V> = { [P in K]: V }
type Flags = Record<"a" | "b", boolean>
const f: Flags = { a: true, b: false }
console.log(f.a)

Named Keys Plus Catch-All

An index signature can mix a catch-all with fixed keys in one interface — handy when you need both. Record alone cannot combine required named keys with an open catch-all as cleanly.

interface Response {
  status: number
  [header: string]: number | string
}
const r: Response = { status: 200, "x-id": "abc" }
console.log(r.status)

Choosing in Practice

Rule of thumb: finite, known keys → Record<Union, V> for completeness checking. Unbounded keys → either form. Need named keys plus a catch-all → index signature inside an interface.

type Status = "ok" | "error"
type Messages = Record<Status, string>
const msg: Messages = { ok: "done", error: "failed" }
console.log(msg.ok)

Quick Check

Test your understanding of Record versus index signatures.

Recap

Record<string, V> equals a string index signature, but Record with a literal key union makes every listed key required, catching omissions at compile time. Use Record<Union, V> for finite known keys, either form for unbounded keys, and an index signature when you need named keys plus a catch-all. Under the hood, Record is the mapped type { [P in K]: V }.

Frequently asked questions

Is the “Index Signatures vs Record” lesson free?

Yes — the full text of “Index Signatures vs Record” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.

What will I learn in “Index Signatures vs Record”?

Choose between index signatures and the Record utility type. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start TypeScript Academy?

No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Index Signatures vs Record” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this TypeScript Academy lesson?

Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Defining Index Signatures
  2. String vs Number Index Signatures
  3. Combining Known and Dynamic Keys
  4. Index Signatures vs Record
← Back to TypeScript Academy