This error occurs when TypeScript cannot verify that a string value matches a template literal type pattern. It commonly happens with template string expressions and dynamic values that TypeScript evaluates as the generic string type.
This error appears when you try to assign a value to a variable or parameter that has a template literal type, but TypeScript cannot confirm the value matches the pattern. Template literal types, introduced in TypeScript 4.1, allow you to define precise string patterns using backticks and placeholders like `${string}` or `${number}px`. The core issue is that TypeScript often evaluates template string expressions to the generic `string` type rather than the more specific template literal type, even when the value would match at runtime. This happens because TypeScript's type system performs static analysis and cannot always infer the exact string pattern from dynamic expressions. Prior to TypeScript 4.3, this was a common limitation where arbitrary template literal types couldn't be assigned to each other. While improvements were made in 4.3 with better assignability rules, certain scenarios still trigger this error, particularly when using variables in template literals or complex nested patterns.
The most direct solution is to use a type assertion when you're confident the value matches the pattern:
type PixelValue = `${number}px`;
// Error: Type 'string' is not assignable to type '`${number}px`'
const width: PixelValue = `22px`;
// Fix: Use type assertion
const width: PixelValue = `22px` as PixelValue;
// Or with angle bracket syntax
const height = <PixelValue>`44px`;This tells TypeScript to trust that the value matches the pattern. Use this when you're certain the runtime value will always be valid.
If the value is truly static, use a plain string literal instead of a template literal:
type StatusMessage = `Status: ${string}`;
// Instead of this (causes error):
const message: StatusMessage = `Status: ${status}`;
// Use this if the value is static:
const message: StatusMessage = 'Status: Success';
// Or construct it differently:
function createStatusMessage(status: string): StatusMessage {
return `Status: ${status}` as StatusMessage;
}This approach works when you don't need dynamic interpolation at the assignment point.
Build a type-safe constructor function that validates and returns the template literal type:
type PixelValue = `${number}px`;
function createPixelValue(value: number): PixelValue {
return `${value}px` as PixelValue;
}
// Type-safe usage
const width = createPixelValue(22); // PixelValue
// With validation
function toPixelValue(input: string): PixelValue | null {
const match = input.match(/^(\d+)px$/);
if (!match) return null;
return input as PixelValue;
}This centralizes the type assertion and can include runtime validation logic.
When working with actual string literals, use as const to preserve the exact literal type:
type EventName = `on${Capitalize<string>}`;
// This works - literal is preserved
const event1: EventName = 'onClick';
// This fails even with as const on the variable
const eventBase = 'click' as const;
const event2: EventName = `on${eventBase}`; // Error
// Fix: Use satisfies operator (TypeScript 4.9+)
const event3 = `onClick` satisfies EventName;
// Or assertion on the full expression
const event4: EventName = 'onClick' as const;The satisfies operator provides type checking without widening the type.
If you're using intricate patterns like multiple interpolations, consider breaking them down:
// Complex pattern that may cause issues
type Complex = `${string}:${number}:${string}`;
// Simplify or use union types instead
type SimplePrefix = `prefix:${string}`;
type SimpleSuffix = `${string}:suffix`;
type Combined = SimplePrefix | SimpleSuffix;
// Or use a broader type
type Flexible = `${string}:${string}`;Simpler patterns are more reliably checked by TypeScript's type system.
Many template literal type assignability issues were fixed in TypeScript 4.3 and later versions:
# Check your TypeScript version
npx tsc --version
# Upgrade to latest version
npm install -D typescript@latest
# Or upgrade to specific version
npm install -D typescript@^5.0.0Update your tsconfig.json to use the new version:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext"
}
}TypeScript 4.3 added assignability rules for template literal types, and 4.9 added the satisfies operator which helps with these scenarios.
TypeScript Compiler Limitations
TypeScript's type system performs static analysis without executing code, which means it cannot evaluate template string expressions to determine their exact runtime value. When you write ${value}px, TypeScript only knows this produces a string, not specifically a string matching the ${number}px pattern.
Template Literal Type Inference
The type inference for template literal types follows specific rules. A template literal type A is assignable to template literal type B when every possible string that A can represent is also representable by B. This means user_${string} is assignable to ${string}, but not the reverse.
String Widening Behavior
TypeScript widens template string expressions containing variables to the string type even when those variables are declared with as const. This is because the template literal itself creates a new value, and TypeScript conservatively treats this as producing a general string rather than a specific pattern.
When to Use Type Assertions
Type assertions with template literal types are generally safe when:
- You control the input values and can guarantee they match the pattern
- You have runtime validation ensuring the pattern is correct
- The pattern is simple enough that manual verification is straightforward
Avoid assertions when dealing with user input or external data without validation, as this bypasses TypeScript's type safety.
Related GitHub Discussions
The TypeScript team has extensively discussed template literal type assignability in issues #43243, #41732, and #57355. PR #43361 (merged in TypeScript 4.3) improved relations and inference between template literal types, but some edge cases remain, particularly with complex nested patterns and certain forms of string interpolation.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript