How to fix Type 'X' is not assignable to template literal type 'Y' in TypeScript
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.
Quick fix
Fixes Type 'X' is not assignable to template literal type 'Y'
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`;- Use type assertions to explicitly cast the value
- Declare string literals directly instead of using template syntax
- Create a helper function with proper type guards
- Use const assertions for literal values
type PixelValue = `${number}px`;// Error: Type 'string' is not assignable to type '`${number}px`'const width: PixelValue = `22px`;// Fix: Use type assertionconst width: PixelValue = `22px` as PixelValue;// Or with angle bracket syntaxconst height = <PixelValue>`44px`;Type 'X' is not assignable to template literal type 'Y'
What this error means
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.
Typical symptoms
- TypeScript compiler error when assigning template strings to template literal type variables
- Error appears even though the runtime value would be valid
- Type checking fails for string variables interpolated in template literals
- Works with literal values but fails with const variables using "as const"
- Complex template patterns like `${string}${number}${string}` reject valid matching strings
Common causes
- Template string expression is widened to generic "string" type instead of preserving the literal pattern
- Using variables in template literals causes TypeScript to lose type information even with const assertions
- TypeScript lacks sophisticated assignability rules for all template literal type combinations
- Multiple interpolations in template literal types create patterns TypeScript cannot verify statically
- Type narrowing is not applied to template string expressions in the same way as string literals
How to fix "Type 'X' is not assignable to template literal type 'Y'"
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.
Advanced notes
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.
Frequently asked questions
- What does "Type 'X' is not assignable to template literal type 'Y'" mean?
- 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. 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.
- How do I fix "Type 'X' is not assignable to template literal type 'Y'"?
- 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.
- What causes "Type 'X' is not assignable to template literal type 'Y'"?
- Template string expression is widened to generic "string" type instead of preserving the literal pattern Using variables in template literals causes TypeScript to lose type information even with const assertions TypeScript lacks sophisticated assignability rules for all template literal type combinations
- Is the "Type 'X' is not assignable to template literal type 'Y'" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐TypeScript Official Documentation
- ๐Typescriptlang.org - type-compatibility.html(Official Docs)
- ๐Typescriptlang.org - template-literal-types.html(Official Docs)
- ๐Github.com - 43243(GitHub)
- ๐Github.com - 41732(GitHub)
- ๐Github.com - 43361(GitHub)