As Const And Enums
as const — freeze a value into its most specific type
By default TypeScript widens literals ("a" becomes string). as const stops that: it locks the value to its exact literal type and makes it deeply readonly.
let a = 1 as const; // type: 1 (not number)
const b = "hello" as const; // type: "hello"
const SKILL_LEVELS = ["Beginner", "Intermediate", "Expert"] as const;
// type: readonly ["Beginner", "Intermediate", "Expert"]
// without `as const` it would be: string[]
Why as const is so useful — derive unions from data
Once an array is as const, you can index it by [number] to get a literal union — one source of truth for both the runtime values and the type.
const SKILL_LEVELS = ["Beginner", "Intermediate", "Expert"] as const;
type Person = {
name: string;
skillLevel: (typeof SKILL_LEVELS)[number]; // "Beginner" | "Intermediate" | "Expert"
};
// the same array still works at runtime:
SKILL_LEVELS.forEach((level) => console.log(level));
Change the array and the type updates itself — no duplicated union to maintain.
enum vs as const — a real distinction
An enum is a TypeScript feature that also emits runtime code (an object) — it's not erased like the rest of the type system.
enum Direction { Up, Down } // compiles to a real JS object at runtime
A const array + as const gives you the same "fixed set of values," stays plain data, and adds zero runtime cost. Many teams prefer the as const union over enum for exactly that reason.
as constsays "this literal is final — narrow it, don't widen it." It's the idiomatic, runtime-free way to build a fixed set of options and derive a union type from it.