Question

What `as const` Means in TypeScript and When to Use It

typescripttype-assertion

Question

I am confused about the as const assertion in TypeScript. I have looked at documentation and videos, but I still do not fully understand it.

What does as const mean in the code below, and what is the benefit of using it?

const args = [8, 5] as const;
const angle = Math.atan2(...args);
console.log(angle);

Short Answer

By the end of this page, you will understand what as const does in TypeScript, how it changes literal inference, why arrays become readonly tuples, and when it is useful in everyday code. You will also see how it helps functions like Math.atan2(...args) type-check correctly.

Concept

as const is a const assertion in TypeScript. It tells TypeScript to infer the most specific, narrowest possible type for a value instead of a wider, more general one.

In practice, as const does three important things:

  • It keeps literal values as literal types.
  • It makes object properties readonly.
  • It turns array literals into readonly tuples.

Consider this example:

const args = [8, 5];

Without as const, TypeScript usually infers:

number[]

That means: “this is an array of numbers of any length.”

But with:

const args = [8, 5] as const;

TypeScript infers:

readonly [8, 5]

That means: “this is a tuple with exactly two items, where the first is 8 and the second is 5, and the tuple cannot be mutated.”

This matters because some functions expect a fixed number of arguments. Math.atan2 takes exactly two arguments:

Math.atan2(y, x)

When you write:

Math.atan2(...args)

TypeScript needs to know that args contains exactly two values. A plain number[] does not guarantee that. A tuple does.

So the benefit of as const here is that it preserves the array as a fixed two-value tuple, allowing the spread call to be type-safe.

This feature matters in real programming because it helps TypeScript catch mistakes earlier. It is especially useful with:

  • configuration objects
  • action type constants
  • fixed option lists
  • function arguments stored in arrays
  • discriminated unions
  • lookup objects

In short, as const makes your values more precise, which makes your types safer.

Mental Model

Think of TypeScript as trying to label boxes.

Without as const, if it sees this:

[8, 5]

it puts a broad label on the box:

  • “This box contains numbers.”

It does not promise how many numbers there are.

With as const, TypeScript puts a much more exact label on the box:

  • “This box contains exactly two items: first 8, then 5, and nobody should change them.”

That extra precision is why spreading the array into a function works better. The function can trust the shape of the data.

So as const is like telling TypeScript:

  • “Do not generalize this value.”
  • “Keep it exactly as written.”
Take Quiz

Syntax and Examples

The basic syntax is:

const value = expression as const;

Example 1: Literal values stay narrow

const status1 = "ok";
const status2 = "ok" as const;

status1 is often inferred as:

"ok"

But as const is especially useful in objects and arrays, where TypeScript would otherwise widen values more often.

Example 2: Object properties become readonly

const config = {
  mode: "dark",
  fontSize: 16,
} as const;

Type:

{
  readonly mode: "dark";
  readonly fontSize: 16;
}

This means:

  • mode is exactly "dark", not just string
  • fontSize is exactly 16, not just number
  • properties cannot be reassigned
// Error
config.mode = "light";

Example 3: Arrays become readonly tuples

const point = [10, 20] as const;

Type:

readonly [10, 20]

This is different from:

const point = [10, 20];

Type:

number[]

Example 4: Why it helps with function arguments

const args = [8, 5] as const;
const angle = Math.atan2(...args);

Because args is a tuple of exactly two items, TypeScript knows it is safe to spread into Math.atan2(y, x).

Without as const:

const args = [8, 5];
const angle = Math.atan2(...args);

TypeScript may complain because args is just number[], and a number[] could have 0, 1, 2, or many values.

Example 5: Useful for fixed lists

const roles = ["admin", "editor", "viewer"] as const;

Now each item is a specific string literal, which is useful for deriving union types:

type Role = typeof roles[number];
// "admin" | "editor" | "viewer"

Step by Step Execution

Consider this code:

const args = [8, 5] as const;
const angle = Math.atan2(...args);
console.log(angle);

Step 1: Create the array literal

[8, 5]

This is an array literal with two numbers.

Step 2: Apply as const

const args = [8, 5] as const;

TypeScript infers the type as:

readonly [8, 5]

That means:

  • first item is 8
  • second item is 5
  • there are exactly two items
  • the tuple is readonly

Step 3: Spread the tuple into the function call

Math.atan2(...args)

This becomes equivalent to:

Math.atan2(8, 5)

TypeScript accepts this because the tuple guarantees two elements.

Step 4: Compute the angle

Math.atan2(y, x) returns the angle in radians from the positive x-axis to the point (x, y).

So here:

  • y = 8
  • x = 5

Step 5: Print the result

console.log(angle);

The output is a number in radians.

Compare with no as const

const args = [8, 5];
const angle = Math.atan2(...args);

Now args is typed as:

number[]

A number[] does not guarantee exactly two elements, so TypeScript cannot safely assume it matches the function signature.

Real World Use Cases

as const is useful whenever a value should be treated as fixed and precise.

1. API request methods

const METHODS = ["GET", "POST", "PUT", "DELETE"] as const;
type HttpMethod = typeof METHODS[number];

This creates a safe union of allowed method names.

2. Redux-style action objects

const action = {
  type: "INCREMENT",
} as const;

Now type is exactly "INCREMENT", which helps with action type checking.

3. Configuration objects

const settings = {
  theme: "dark",
  layout: "grid",
} as const;

Useful when settings should not be changed accidentally.

4. Route definitions

const routes = ["/", "/login", "/dashboard"] as const;

You can derive a union of valid route strings.

5. Fixed coordinate or argument lists

const rgb = [255, 120, 0] as const;

This is useful when a function expects a fixed number of values.

6. Status values

const statuses = ["idle", "loading", "success", "error"] as const;
type Status = typeof statuses[number];

This helps avoid typos like "sucess".

Take Quiz

Real Codebase Usage

In real projects, developers use as const to improve type safety without writing extra type definitions.

Common patterns

Guarding fixed values

const VALID_STATUSES = ["pending", "paid", "failed"] as const;
type Status = typeof VALID_STATUSES[number];

This keeps allowed values in one place.

Safer configuration

const APP_CONFIG = {
  env: "production",
  retries: 3,
} as const;

This prevents accidental mutation and preserves precise values.

Action creators

const setCount = (count: number) => ({
  type: "SET_COUNT",
  payload: count,
} as const);

This helps TypeScript distinguish one action type from another.

Mapping names to constant values

const COLORS = {
  primary: "#3366ff",
  danger: "#ff3333",
} as const;

This gives readonly properties and exact string values.

Fixed argument tuples

const pair = [10, 20] as const;
someFunction(...pair);

This is especially common when passing prebuilt arguments into a function.

Why teams like it

  • less manual type writing
  • better autocomplete
  • fewer invalid values
  • safer refactoring
  • improved support for union types and discriminated unions

Common Mistakes

1. Thinking as const is the same as const

These are different.

const name = "Sam";

const means the variable cannot be reassigned.

const user = { name: "Sam" };

You still can do this:

user.name = "Alex";

But with as const:

const user = { name: "Sam" } as const;

Now this is an error:

user.name = "Alex";

2. Using as const when you actually need mutability

Broken idea:

const numbers = [1, 2, 3] as const;
numbers.push(4); // Error

If you plan to change the array, do not use as const.

3. Assuming it affects runtime behavior

as const is only for TypeScript's type system. It does not freeze the value at runtime.

const obj = { x: 1 } as const;

This adds compile-time readonly typing, not JavaScript runtime immutability like Object.freeze().

4. Overusing it everywhere

Not every value needs maximum precision. Use it when exact literals or readonly tuples are actually helpful.

5. Confusing tuples with arrays

const values = [1, 2] as const;

This is not a normal mutable number[]. It is a readonly tuple.

6. Expecting spread calls to work with normal arrays

Broken example:

const args = [8, 5];
Math.atan2(...args); // May produce a type error

Fix:

const args = [8, 5] as const;
Math.atan2(...args);

Or explicitly type the tuple:

const args: [number, number] = [8, 5];
Math.atan2(...args);

Comparisons

ConceptWhat it doesMutabilityExample inferred type
const x = ...Prevents variable reassignmentValue may still be mutableconst arr = [1, 2] -> number[]
as constPreserves exact literal typesReadonly at type levelreadonly [1, 2]
Explicit type annotationYou manually choose the typeDepends on the typeconst arr: [number, number] = [1, 2]

const vs as const

const arr1 = [8, 5];
// type: number[]

const arr2 = [8, 5] as const;
// type: readonly [8, 5]

const only stops reassignment of arr1 or arr2. as const changes how TypeScript infers the inner value.

as const vs explicit tuple type

const a = [8, 5] as const;
// readonly [8, 5]

const b: [number, number] = [8, 5];
// [number, number]

Use as const when you want the exact literal values and readonly behavior.

Use an explicit tuple type when you want fixed length but not exact literal values.

as const vs Object.freeze()

const obj = { mode: "dark" } as const;
const frozen = Object.freeze({ mode: "dark" });
  • as const is a TypeScript type assertion
  • Object.freeze() is a JavaScript runtime operation

They solve related but different problems.

Take Quiz

Cheat Sheet

Quick rules

  • as const tells TypeScript to keep a value as specific as possible.
  • String, number, and boolean literals stay literal.
  • Object properties become readonly.
  • Arrays become readonly tuples.

Syntax

const value = expr as const;

Common examples

const status = "ok" as const;
// type: "ok"

const point = [10, 20] as const;
// type: readonly [10, 20]

const config = { theme: "dark" } as const;
// type: { readonly theme: "dark" }

Good use cases

  • fixed lists of allowed values
  • action type objects
  • function argument tuples
  • config objects that should not change
  • deriving union types from arrays

Important note

const arr = [1, 2] as const;

This means:

  • exact values
  • exact length
  • readonly tuple

It does not mean runtime freezing.

Alternative

If you want a fixed-length tuple without literal values:

const args: [number, number] = [8, 5];

FAQ

What does as const do in TypeScript?

It tells TypeScript to infer the narrowest possible type for a value, making literals exact, object properties readonly, and arrays readonly tuples.

Why is as const useful with arrays?

It turns an array literal into a readonly tuple, which is helpful when a function expects a fixed number of arguments.

Why does Math.atan2(...args) work better with as const?

Because Math.atan2 expects exactly two arguments, and as const tells TypeScript that args contains exactly two items.

Is as const the same as const?

No. const prevents variable reassignment. as const changes type inference to be more specific.

Does as const freeze objects at runtime?

No. It only affects TypeScript's compile-time type checking. It does not make the object truly immutable in JavaScript.

When should I avoid as const?

Avoid it when you need to mutate the object or array later, because it makes properties and tuple elements readonly.

Can I use an explicit type instead of as const?

Yes. For example, const args: [number, number] = [8, 5]; also works for fixed-length tuples.

Is as const only for arrays?

No. It also works with strings, numbers, booleans, and object literals.

Take Quiz

Mini Project

Description

Build a small TypeScript utility for application statuses. The project demonstrates how as const helps define a fixed list of allowed values and safely validate user input against that list.

Goal

Create a type-safe status system using as const, then validate and print statuses without allowing invalid values.

Requirements

  • Create a constant array of allowed statuses using as const.
  • Derive a Status type from that array.
  • Write a function that checks whether a string is a valid status.
  • Write a function that prints a message for a valid status.
  • Test the code with both valid and invalid input.
Take Quiz

Keep learning

Related questions

View more