Fixing TypeScript Error: 'const' assertion can only be applied to a string, number, boolean, array, or object literal

intermediate🔵 TypeScript2026-04-30| TypeScript 3.4+ environments (Node.js, React, Vue, Angular) using VS Code or terminal compilers.

Error Message

A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
#typescript#const-assertion#as-const#literal-type

Beyond the Red Squiggly LineI was refactoring a permissions module for a production release when TypeScript stopped me cold. I wanted to ensure a configuration object was treated as a deeply immutable literal type. Instead of the clean, read-only types I expected, the compiler threw a familiar error: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.

This happens when you try to apply as const to a value that TypeScript no longer sees as a literal expression. It’s a common hurdle when hardening type safety in large-scale projects.

The Error Message```

// This code usually triggers the error: const userRoles = ['admin', 'editor', 'viewer']; const ROLES = userRoles as const; // ❌ Error here!


The compiler output is direct but can be confusing if you don't know about type widening:

error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.


## Root Cause: Type WideningTypeScript introduced the `as const` assertion in version 3.4. Its primary job is to tell the compiler that an expression should be a literal type—like the specific string "admin" instead of the generic `string`—and that all members should be `readonly`.
However, **`as const` must be applied at the point of creation.**
In the example above, `userRoles` is already a variable. By the second line, TypeScript has already "widened" `userRoles` to the general type `string[]`. You cannot apply a `const` assertion to a reference that has already lost its literal specificity. The compiler requires the assertion to sit directly on the data structure itself.
## How to Fix It### Approach 1: Assert at the SourceThe most effective fix is to move the `as const` assertion to the literal value before assigning it to a variable. This prevents the compiler from ever widening the type.

// ✅ Do this instead const ROLES = ['admin', 'editor', 'viewer'] as const;

// ROLES is now: readonly ["admin", "editor", "viewer"]


By placing the assertion directly after the array bracket, you tell TypeScript to keep those three specific strings exactly as they are. This reduces the type from an infinite set of strings to a fixed tuple of three.
### Approach 2: Handling Ternaries and LogicYou might encounter this when using a ternary operator or a template literal. If the expression is complex, the compiler might lose track of the literal values.

// ❌ This often fails in complex scenarios const status = (isActive ? 'active' : 'inactive') as const;

// ✅ Fix: Assert individual literals const status = isActive ? ('active' as const) : ('inactive' as const);


While modern TypeScript versions handle simple ternaries better, wrapping individual results in parentheses is the safest way to guarantee literal types.
### Approach 3: The 'satisfies' Operator (TS 4.9+)If you are on TypeScript 4.9 or later, the `satisfies` operator is often better than `as const`. It allows you to validate a shape while retaining literal types.

type Config = Record<string, string[]>;

// ✅ Best of both worlds const menu = { home: ['/'], auth: ['/login', '/signup'] } as const satisfies Config;


This approach ensures the object is `readonly`, keeps specific string values, and verifies the object matches your `Config` interface.
### Approach 4: Template Literal SpecificsWhen building dynamic strings, ensure the base components are literals. If a prefix is already widened to a general `string`, the final template literal cannot be asserted back to a constant.

const prefix = 'API'; // Defaults to literal "API" const endpoint = ${prefix}_URL as const; // This works!


## Verification StepsTo confirm the fix, hover over your variable in VS Code. You should see specific values in the type definition, not just `string` or `string[]`.
- **Success:** You see `readonly ["value1", "value2"]`.- **Failure:** You still see generic types like `string[]`.Run a quick type check to be certain:

npx tsc --noEmit


## Prevention Tips- **Declare early:** Apply `as const` the moment you define your configuration objects.- **Prefer Readonly:** Use `ReadonlyArray<T>` in function signatures to signal immutability requirements.- **Avoid 'let':** Use `const` for all variable declarations to prevent the compiler from assuming the value will change later.

Related Error Notes