Skip to content

as const in TypeScript: Const Assertions Explained

as const is a TypeScript feature known as a const assertion that transforms how TypeScript infers types for your values, making them more specific and immutable.

What Does as const Do?

When you use as const, TypeScript infers the narrowest possible type for an expression. This means:

  • Literal types are not widened (e.g., "success" stays as literal type "success" instead of being widened to string)
  • Object literals get readonly properties
  • Array literals become readonly tuples

Key Benefits

1. Tuple Type Safety

Consider the original example:

typescript
// Without as const: args is inferred as number[]
const args = [8, 5];
const angle = Math.atan2(...args); // Error: Expected 2 arguments
typescript
// With as const: args is readonly [8, 5]
const args = [8, 5] as const;
const angle = Math.atan2(...args); // Works perfectly

The as const assertion tells TypeScript that args is a tuple with exactly two numbers in specific positions.

2. Immutable Data Structures

typescript
const config = {
  host: "localhost",
  port: 8080,
  ssl: true
} as const;

// All these will cause compilation errors:
config.host = "example.com";     // ❌ Cannot assign to 'host'
config.port = 3000;             // ❌ Cannot assign to 'port'
delete config.ssl;              // ❌ Cannot delete

3. Preventing Type Widening

typescript
type Status = "success" | "danger";

function showStatus(status: Status) {
  console.log(status);
}

const status = "success"; // Type is string, not "success"
showStatus(status);       // ❌ Error: string not assignable to Status
typescript
const status = "success"; // Type: string
showStatus(status);       // Error
typescript
const status = "success" as const; // Type: "success"
showStatus(status);                // Works

How It Differs From Regular const

Regular const only prevents variable reassignment, not mutation of the referenced object:

typescript
const regularArray = [1, 2, 3];
regularArray[0] = 999;     // ✅ Allowed
regularArray.push(4);      // ✅ Allowed

const constArray = [1, 2, 3] as const;
constArray[0] = 999;       // ❌ Error: readonly
constArray.push(4);        // ❌ Error: no push method

Common Use Cases

1. Configuration Objects

typescript
const APP_CONFIG = {
  version: "1.0.0",
  apiUrl: "https://api.example.com",
  retryAttempts: 3,
  timeout: 5000
} as const;

// Type is inferred as:
// {
//   readonly version: "1.0.0";
//   readonly apiUrl: "https://api.example.com";
//   readonly retryAttempts: 3;
//   readonly timeout: 5000;
// }

2. Redux/Action Creators

typescript
const setUser = (user: User) => ({
  type: "SET_USER" as const,
  payload: user
});

// Type is properly narrowed to:
// { readonly type: "SET_USER"; readonly payload: User; }

3. Function Parameters

typescript
function calculateArea(dimensions: readonly [number, number]) {
  return dimensions[0] * dimensions[1];
}

const dims = [10, 20] as const;
calculateArea(dims); // ✅ Works with readonly tuple

Limitations and Considerations

WARNING

as const is a compile-time only feature. At runtime, JavaScript objects remain mutable - TypeScript only prevents you from writing code that would mutate them.

INFO

There are some edge cases where as const doesn't make everything completely readonly. Check the TypeScript documentation for details.

When to Use as const

  • When you need to pass literal values to functions expecting specific types
  • When creating configuration objects that shouldn't be modified
  • When working with tuples that have fixed lengths and types
  • When you want to prevent accidental mutations in your codebase

Conclusion

as const is a powerful TypeScript feature that enables more precise type inference and immutability at the type level. It helps catch bugs at compile time by making your intentions explicit to the TypeScript compiler, leading to more robust and maintainable code.