Unlock Literal Types: The Magic of as const in TypeScript

3 min read
By:
James Perkins James Perkins

An often underutilized, feature within TypeScript that enhances type safety and code predictability: the as const assertion.

In standard TypeScript behavior, literal types are often "widened" to their broader primitive types. For instance, declaring const statusCode = 200; will result in statusCode being inferred as number, not the specific literal 200.

Similarly, an array like const colors = ["red", "green"]; would typically be inferred as string[], meaning an array of any strings, not specifically an array containing only "red" and "green". While this widening is generally beneficial for flexibility, there are numerous scenarios where maintaining the narrowest possible type is crucial.

This is where as const shines. By appending as const to a variable declaration or an expression, you instruct the TypeScript compiler to infer the narrowest possible type for that entity, making it deeply immutable and literal-typed.

Let's look an example with an Object:

        const API_ENDPOINTS = {
  users: "/api/v1/users",
  products: "/api/v1/products",
  orders: "/api/v1/orders",
} as const;

// Without as const, API_ENDPOINTS.users would be inferred as string.

// With as const, API_ENDPOINTS.users is now strictly "/api/v1/users".
      

The immediate benefit here is type inference. API_ENDPOINTS.users is no longer just a string; it's the literal string "/api/v1/users". This means if you tried to assign API_ENDPOINTS.users = "/api/v1/new-users";, TypeScript would throw an error, preventing accidental modification and ensuring that your constants truly remain constant. Furthermore, if you're building a function that expects a specific endpoint string, API_ENDPOINTS.users perfectly matches that type, providing autocomplete and compile-time checks.

You can use it with arrays and tuples as well:

        const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE"] as const;

// Without as const, HTTP_METHODS would be string[].

// With as const, HTTP_METHODS is a tuple readonly ["GET", "POST", "PUT", "DELETE"].
      

Here, HTTP_METHODS is inferred as a readonly tuple, making both the array itself immutable and its elements literal types. This is incredibly powerful for defining fixed sets of options or states, preventing runtime errors caused by unexpected values.

Key Benefits of as const:

1. Enhanced Type Safety: Prevents accidental modification of "constants" and ensures that literal values are preserved throughout your codebase.

2. Improved Autocomplete: Your IDE can offer more precise suggestions based on the literal types, boosting developer productivity. If you are using AI this means they are less likely to mess it up.

3. Richer Type Inference: Allows TypeScript to infer more specific and useful types, leading to more robust and less error-prone code.

4. Enforces Immutability: When applied to objects or arrays, it makes them deeply readonly, preventing any future modifications. This aligns well with functional programming paradigms and helps avoid subtle bugs caused by mutable state.

5. Better switch Statements and Conditional Logic: With literal types, switch statements can be exhaustive, and conditional logic can be more precise, as the compiler knows the exact possible values.

as const is a simple yet impactful addition to your TypeScript toolkit. It allows you to declare constants that truly behave as constants from a type perspective, leading to more predictable, maintainable, and robust applications.