Use as const in TypeScript
The as const assertion tells TypeScript to treat a value as fully immutable with literal types. Learn when to use it, what it does to objects and arrays, and how it enables enum-like patterns.
The as const assertion is a TypeScript feature that tells the compiler to treat a literal value as completely immutable and to infer the narrowest possible types. It was introduced in TypeScript 3.4 and has become the standard way to create deeply typed constant data.
With as const, string values get literal types, numbers get numeric literal types, object properties become readonly, and arrays become readonly tuples. A single keyword does all of this at once.
const theme = "dark" as const;
// Type: "dark"
const sizes = ["small", "medium", "large"] as const;
// Type: readonly ["small", "medium", "large"]
const config = { api: "v2", port: 3000 } as const;
// Type: { readonly api: "v2"; readonly port: 3000 }Each value keeps its exact type. The string is not just a string, it is that specific string. The array is not just a string array, it is a fixed-length tuple with known elements.
The object properties cannot be reassigned.
What As Const Does
The as const assertion does three things to any literal expression. First, it prevents type widening so every value keeps its literal type instead of widening to a general type. Second, it marks all object properties as readonly.
Third, it converts array literals to readonly tuples with literal element types.
These changes are deep. Every nested object and array inside the expression inherits the same treatment. A single assertion at the top level flows through the entire value tree, which means you do not need to add readonly or literal annotations at each level.
The assertion only works on literal expressions. You cannot apply it to computed values, function return values, or variables that hold runtime-determined data. The compiler must be able to evaluate the expression at compile time to infer the literal types.
Objects with As Const
The most common use of as const is on configuration objects. Without it, TypeScript infers general types that allow mutation and lose the specific values.
const settings = {
theme: "dark",
version: 2,
} as const;
settings.theme = "light";
// Error: Cannot assign to 'theme' because it is a read-only propertyEvery property is now readonly and has a literal type. The compiler rejects any attempt to reassign a property. This catches accidental mutations in configuration that should be fixed for the lifetime of the application.
For more on how readonly works independently of as const, see Readonly values in TypeScript.
Arrays with As Const
Arrays with as const become readonly tuples. Each element keeps its literal type, and all mutating methods are blocked. This is useful when you need a fixed sequence of values that should never change.
const directions = ["north", "south", "east", "west"] as const;
// Type: readonly ["north", "south", "east", "west"]
directions.push("up");
// Error: Property 'push' does not existYou can derive a union type from the array, avoiding duplication. The type expression extracts each element's literal type and combines them into a union. This keeps the array as the single source of truth for both runtime and compile-time usage.
type Direction = (typeof directions)[number];
// Type: "north" | "south" | "east" | "west"This pattern is widely used for string constants, HTTP methods, status values, and any set of known options that need both a runtime array and a compile-time type.
Enum-Like Patterns
As const can replace TypeScript enums in many cases. An as const object provides named constants with exact literal types, without the runtime overhead of TypeScript's enum feature.
const Status = {
Active: "ACTIVE",
Inactive: "INACTIVE",
Pending: "PENDING",
} as const;
type StatusType = (typeof Status)[keyof typeof Status];
// Type: "ACTIVE" | "INACTIVE" | "PENDING"This approach is lighter than enums because it does not generate extra JavaScript. It also integrates naturally with APIs that expect string values, since each value is already a plain string. For more on literal types, see TypeScript literal types explained.
As Const Limitations
As const only applies to literal expressions. You cannot use it on computed expressions because the compiler needs to know the exact value at compile time. A ternary expression or an arithmetic result cannot be asserted with as const.
It also does not deeply freeze at runtime. It is a type-level only directive. The JavaScript output is unchanged, so if another piece of code has a reference to the same object without the readonly type, it can still mutate the data.
The protection is at the type-checking level, not at the JavaScript runtime level.
Nested mutable references inside an as const object are still readonly at their reference level, but the values they point to might be mutable if they are shared references. This is the same behavior as readonly properties in general.
When to Use As Const
Use as const on configuration objects that should never change during the application's life. Use it on arrays of known values when you need both runtime iteration and compile-time type unions. Use it on string constants to create enum-like patterns without generating extra JavaScript.
Skip as const on data that is intentionally mutable. Do not use it on API responses, user input, or any value that comes from an external source. The assertion is for values that you define and control at compile time.
For how as const relates to the wider type inference system, see Type widening in TypeScript.
Rune AI
Key Insights
- as const locks an object or array into its most specific literal type.
- All properties become readonly; arrays become readonly tuples.
- It only works on literal expressions, not computed values.
- Use as const for configuration, string constants, and enum-like patterns.
- No runtime effect: as const is erased during compilation.
Frequently Asked Questions
What is the difference between const and as const?
Does as const affect runtime behavior?
Can I use as const on a let variable?
Conclusion
as const is the simplest way to tell TypeScript that a value is truly fixed. It infers the narrowest possible literal types, marks every property as readonly, and turns arrays into readonly tuples. Use it on configuration objects, string constants, and any data structure that should not change. It has zero runtime cost and makes your types more precise with a single keyword.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.