TSworkingts-evergreen

const assertions (as const)

Freeze the value, keep the literals.

as const tells TypeScript to infer the narrowest possible type β€” literal strings instead of string, readonly tuples instead of arrays β€” which is the key to deriving union types from plain data.

What as const actually does

Append as const to a literal and TypeScript stops widening. A bare let x = 'GET' is inferred as string; const x = 'GET' as const is the literal type 'GET'. Applied to an array or object, the assertion goes all the way down: every property becomes readonly, every nested array becomes a readonly tuple, and every primitive keeps its literal type instead of collapsing to string / number / boolean.

Why narrow types are worth it

Literal types are what let you derive other types from a value. A readonly ['red', 'green', 'blue'] tuple can be turned into the union 'red' | 'green' | 'blue' with typeof arr[number] β€” so you write the data once and the type follows automatically. Without as const the same array is string[], and typeof arr[number] is just string β€” useless as a constraint.

Tuples, not arrays

as const is also the cleanest way to get a tuple β€” a fixed-length array where each position has its own type. [number, string] instead of (number | string)[]. That makes the readonly pair safe to destructure with the right types, and the compiler will reject pushing onto it or reassigning an element.

Deriving unions and enum-like objects

The pattern typeof obj[keyof typeof obj] reads a union of an object's value types, and keyof typeof obj reads a union of its keys. Pair them with an as const object and you have a lightweight, tree-shakeable alternative to enum β€” plain data at runtime, precise literal types at compile time, no extra emitted code.

as const vs satisfies

as const narrows but never validates β€” a typo'd value is still accepted as its own literal. satisfies validates against a wider type but doesn't narrow. They compose: value as const satisfies SomeType gives you frozen literals and a shape check. Reach for as const when you want the inferred type to be as specific as the data.

Try it 5 examples

Widening vs as const

TSintro
Press Run to execute

All three print GET at runtime, but the types differ: loose.method is the wide string, while tight.method and m are the literal 'GET' β€” so as const changes what the compiler will accept without changing the value.