• Home
  • Skills
  • Projects
  • Blog
  • Contact
Resume
Naser Rasouli

Author

Naser Rasouli

Front-End developer - sharing lessons learned, notes, and write-ups from real projects.

GitHubLinkedIn

Last posts

BEM Methodology in CSS: predictable naming for clean styles
2026-02-18•1 min read

BEM Methodology in CSS: predictable naming for clean styles

A practical guide to BEM to avoid style conflicts, structure class names, and keep CSS maintainable.

Why console.log After setState Shows the Old Value
2026-02-04•1 min read

Why console.log After setState Shows the Old Value

React batches state updates, so logging right after setState prints the previous value. Here’s why and the right ways to read the fresh state.

Cleanup Functions in useEffect: Stop Leaks Before They Start
2026-02-04•1 min read

Cleanup Functions in useEffect: Stop Leaks Before They Start

A practical guide to writing cleanup in useEffect so you avoid memory leaks, duplicate listeners, and setState on unmounted components.

Mastering Record in TypeScript

Mastering Record in TypeScript

2025-12-13
typescriptrecordenumstype-safety

Introduction

Need a reliable way to attach labels, icons, or colors to an enum without scattering switch statements? Record gives you a single, type-safe map so UI metadata stays centralized, predictable, and easy to extend. This guide shows how it works with both union types and real-world enums.


What is Record in TypeScript?

Record<K, T> creates an object type whose keys must be of type K and whose values must be of type T. It is perfect for mapping a fixed set of keys to structured metadata.

// Union type of possible roles
type UserRole = "admin" | "user" | "guest";

// Keys must be each role; values must be strings
const roles: Record<UserRole, string> = {
  admin: "Administrator",
  user: "Regular User",
  guest: "Guest User",
};

// Safe lookup
console.log(roles.admin); // "Administrator"

// Error: TypeScript prevents unknown keys
// roles.superAdmin = "Super Admin";

This pattern guarantees full coverage of all keys and prevents accidental extras.


Using Record with enums (UI metadata)

Enums show up everywhere in production apps. Suppose you need labels and colors for payment statuses:

enum PaymentStatus {
  Unpaid = 0,
  Paid = 1,
  Failed = 2,
}

Instead of repeating switch statements, create one source of truth:

const paymentStatusMeta: Record<
  PaymentStatus,
  { label: string; color: string }
> = {
  [PaymentStatus.Unpaid]: { label: "Unpaid", color: "orange" },
  [PaymentStatus.Paid]: { label: "Paid", color: "green" },
  [PaymentStatus.Failed]: { label: "Failed", color: "red" },
};

Now you can render metadata directly:

const status = PaymentStatus.Paid;
console.log(paymentStatusMeta[status].label); // "Paid"
console.log(paymentStatusMeta[status].color); // "green"

Helper function for cleaner usage

Wrap lookups to keep call sites expressive and future-proof:

function getPaymentStatusMeta(status: PaymentStatus) {
  return paymentStatusMeta[status];
}

// Usage
const info = getPaymentStatusMeta(PaymentStatus.Failed);
console.log(info.label); // "Failed"
console.log(info.color); // "red"

If you later add localization or formatting, you update the function without touching the rest of your codebase.


Why prefer Record over switch/case?

  • Full coverage enforced: TypeScript requires every enum or union key to exist in the map.
  • Strong typing: Values must match the declared shape, preventing accidental mismatches.
  • Centralized metadata: Labels, colors, and icons live in one place.
  • Cleaner reads: meta[status].label is easier to scan than repeated switch statements.
  • Safer extensions: Adding a new enum value forces you to supply its metadata at compile time.

Summary

  • Record<K, T> builds a type-safe map from known keys to structured values.
  • Use it to store UI metadata for enums or union types instead of scattered switches.
  • Wrap lookups in a helper to add localization or formatting later without refactors.
  • The compiler enforces full coverage and correct value shapes, reducing runtime bugs.

Conclusion

Record keeps enum metadata centralized, readable, and type-safe. Use it as the single source of truth for anything your UI needs to display for a given status or role, and let TypeScript enforce completeness for you. Happy coding!