What does "as const" do in TypeScript?

as const freezes a value's type to its most specific literal types, making all values readonly and preventing TypeScript from widening them to general types like string or number.

TypeScript

Overview

`as const` is a const assertion that tells TypeScript: "infer the narrowest possible type for this value." Without it, TypeScript widens literals - `"hello"` becomes `string`, `42` becomes `number`. With `as const`, they stay as the exact literal type.

Key Points

  • •Without `as const`: `{ color: "red" }` has type `{ color: string }` - widened.
  • •With `as const`: `{ color: "red" } as const` has type `{ readonly color: "red" }` - literal, readonly.
  • •Arrays become `readonly` tuples with literal element types.
  • •Useful for defining const maps, lookup tables, and configuration objects used as types.
  • •`Object.keys()` on an `as const` object still returns `string[]` - use `as const` + type helpers for key typing.

Examples

Type widening without vs with as const

typescript
// Without as const - types are widened
const colors = { primary: 'blue', danger: 'red' };
// Type: { primary: string; danger: string }

// With as const - types are literal and readonly
const colors = { primary: 'blue', danger: 'red' } as const;
// Type: { readonly primary: "blue"; readonly danger: "red" }

Derive a union type from an as const object

typescript
const ROUTES = {
  HOME:    '/',
  ABOUT:   '/about',
  PROFILE: '/profile',
} as const;

type Route = typeof ROUTES[keyof typeof ROUTES];
// type Route = '/' | '/about' | '/profile'

function navigate(route: Route) { ... }
navigate('/about');  // OK
navigate('/foo');    // Error: not a valid route

as const arrays become readonly tuples

typescript
const SIZES = ['sm', 'md', 'lg', 'xl'] as const;
// Type: readonly ["sm", "md", "lg", "xl"]

type Size = typeof SIZES[number];
// type Size = "sm" | "md" | "lg" | "xl"

Fixing function argument widening

typescript
function setDirection(dir: 'left' | 'right') { ... }

const dir = 'left';          // inferred as string - too wide!
setDirection(dir);           // Error: string not assignable to 'left' | 'right'

const dir = 'left' as const; // inferred as literal 'left'
setDirection(dir);           // OK

Pro Tip

`as const` is your go-to for extracting union types from a list of constant values. Define your constants in one place, derive the type from them, and both stay in sync automatically: `type Color = typeof COLORS[number]`.