Const Assertions

as const

as const tells TypeScript to infer the narrowest type: string and number literals stay literal, arrays become readonly tuples and object properties become readonly.

Example

const sizes = ["S", "M", "L"];               // string[]
const sizesConst = ["S", "M", "L"] as const; // readonly ["S", "M", "L"]
type Size = (typeof sizesConst)[number];     // "S" | "M" | "L"

const config = { currency: "INR", maxQty: 10 } as const;
// config.currency is "INR", config.maxQty is 10, both readonly

function pickSize(s: Size): string { return "Size " + s; }

console.log(sizes.length, pickSize(sizesConst[1]), config.currency, config.maxQty);

Output

3 Size M INR 10

Readonly Result

Example

Everything under as const is readonly (TS2540, TS2339).

const config = { currency: "INR", tiers: ["silver", "gold"] } as const;
config.currency = "USD";
config.tiers.push("platinum");

Compiler output (tsc)

Line 2: error TS2540: Cannot assign to 'currency' because it is a read-only property.
Line 3: error TS2339: Property 'push' does not exist on type 'readonly ["silver", "gold"]'.

Best of Both: as const satisfies

Example

Combine them to get literal types and a shape check.

type Plan = { name: string; pricePerMonth: number };

const PLANS = [
  { name: "Mobile", pricePerMonth: 149 },
  { name: "Premium", pricePerMonth: 649 },
] as const satisfies readonly Plan[];

type PlanName = (typeof PLANS)[number]["name"]; // "Mobile" | "Premium"
const choice: PlanName = "Premium";
console.log(choice, PLANS.find((p) => p.name === choice)?.pricePerMonth);

Output

Premium 649