Const assertions (as const) in TypeScript
What is as const?
as const is a const assertion that tells TypeScript to infer the narrowest possible type for a value — making it deeply readonly with literal types instead of widened types.
Without vs With as const
typescript
// Without as const — widened types
const config = {
url: "https://api.example.com",
port: 3000,
methods: ["GET", "POST"]
};
// type: { url: string; port: number; methods: string[] }
// With as const — narrowed to literals and readonly
const config = {
url: "https://api.example.com",
port: 3000,
methods: ["GET", "POST"]
} as const;
// type: {
// readonly url: "https://api.example.com";
// readonly port: 3000;
// readonly methods: readonly ["GET", "POST"];
// }What as const Does
| Aspect | Without as const | With as const |
|---|---|---|
| String values | string | Literal ("exact value") |
| Number values | number | Literal (42) |
| Object properties | Mutable | readonly |
| Arrays | Mutable array | readonly tuple |
| Nested objects | Mutable | Deeply readonly |
Common Use Cases
Creating Union Types from Values
typescript
const ROLES = ["admin", "editor", "viewer"] as const;
type Role = typeof ROLES[number]; // "admin" | "editor" | "viewer"
const STATUS = {
PENDING: "pending",
ACTIVE: "active",
INACTIVE: "inactive",
} as const;
type Status = typeof STATUS[keyof typeof STATUS];
// "pending" | "active" | "inactive"Enum Alternative
typescript
// Instead of enum:
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT" }
// Use as const:
const Direction = {
Up: "UP",
Down: "DOWN",
Left: "LEFT",
Right: "RIGHT",
} as const;
type Direction = typeof Direction[keyof typeof Direction];
// "UP" | "DOWN" | "LEFT" | "RIGHT"Function with Literal Return
typescript
function getConfig() {
return {
theme: "dark",
lang: "en",
features: ["search", "notifications"],
} as const;
}
const config = getConfig();
config.theme; // "dark" (literal, not string)
config.features[0]; // "search" (literal)Discriminated Unions
typescript
const createAction = <T extends string, P>(type: T, payload: P) =>
({ type, payload } as const);
const increment = createAction("INCREMENT", { amount: 1 });
// { readonly type: "INCREMENT"; readonly payload: { readonly amount: 1 } }Tuple Arguments
typescript
// Without as const
const args = [1, "hello"]; // (string | number)[]
// With as const
const args = [1, "hello"] as const; // readonly [1, "hello"]
function foo(num: number, str: string) {}
foo(...args); // ✅ Works because TypeScript knows exact typesas const vs Object.freeze
| Feature | as const | Object.freeze |
|---|---|---|
| When | Compile time | Runtime |
| Depth | Deep readonly | Shallow |
| Literal types | Yes | No |
| Runtime effect | None | Prevents modification |
typescript
// For maximum immutability: combine both
const config = Object.freeze({
api: "https://api.example.com",
version: 1,
} as const);Important:
as const is essential for creating type-safe constants, enum alternatives, and literal union types from values. It's a compile-time-only feature with zero runtime cost. Use it whenever you need TypeScript to infer the most specific type possible.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.