How to fix Template literal type cannot contain template literal in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025ยท 102 views

TypeScript emits this error when a template literal placeholder resolves to another template literal type (often via `keyof T` or a mapped alias) and the compiler cannot treat it as a flattened string union. You can fix it by expanding the inner union, narrowing the placeholder to primitives, or using helper inference to rebuild the string.

Quick fix

Fixes Template literal type cannot contain template literal

  1. Flatten the inner template literal before reusing it
  2. Constrain the placeholder to a string-friendly union
  3. Infer and rebuild the string to avoid nested aliases
  4. Generate derived unions explicitly instead of chaining literals
typescript โ€” error
# Template literal type cannot contain template literal
Template literal type cannot contain template literal

What this error means

The compiler produces "Template literal type cannot contain template literal" because it has to resolve the placeholder inside ``...`` to a concrete string-like union. When the placeholder itself is still a template literal type (a union built from `keyof T`, `${string}`, or a helper alias), the compiler refuses to nest another template literal and raises the message to avoid cycles or symbol-induced unions. The error forces you to simplify the inner alias so the outer literal only sees plain string/number-like members, which keeps template literal types tractable and compatible with indexed access.

Typical symptoms

  • tsc stops compiling and reports `Template literal type cannot contain template literal` while building derived string unions
  • The IDE highlights the placeholder inside ```...`` or the inner alias used to build it
  • Happens while deriving names from `keyof T`, mapped-type keys, or string templates that reuse a helper alias
  • The error can appear transiently when refactoring event name helpers or prefixing union members
  • Fixing the inner alias or stripping non-string keys immediately clears the diagnostic

Common causes

  1. You pass another template literal type (for example `type Inner = `${string}``) directly into a template literal placeholder
  2. The helper alias still contains `symbol` keys (e.g. using `keyof T` without excluding symbols) and the compiler rejects the literal
  3. TypeScript cannot simplify the nested literal because it would require enumerating every permutation of the inner union
  4. The placeholder type is not constrained to `string | number | bigint | boolean | null | undefined`, so the compiler treats it as a composite literal
  5. A refactor tries to reuse an existing literal alias instead of the union that produced it, so the outer literal still sees a template literal type

How to fix "Template literal type cannot contain template literal"

1Flatten the inner template literal before reusing it

If you built the inner union with another literal, expand it when building the outer literal instead of nesting the alias:

Problematic pattern:
\\\ts // Inner alias remains a template literal type type ComponentSize = \\${"small" | "large"}\; type ComponentClass = \button-\${ComponentSize}\; // Error: Template literal type cannot contain template literal \\\
Fix: inline the union or limit the alias to primitives so the outer literal sees a string union:
\\\ts type ComponentClass = \button-\${"small" | "large"}\; // Works // or give ComponentSize a plain string union type ComponentSize = "small" | "large"; type ComponentClass = \button-\${ComponentSize}\; \\\

2Constrain the placeholder to a string-friendly union

If the placeholder comes from a generalized helper (often \\\\${keyof T}\\\), restrict it before passing it into another literal:
\\\ts type KeysOf<T extends object> = \\${Extract<keyof T, string | number | bigint | boolean | null | undefined>}\`;

type PrefixedKeys<T extends object> = \on\${Capitalize<KeysOf<T>>}\; // No nested template literal error
\\\ Using \Extract\ or \Exclude<keyof T, symbol>\` keeps the template literal from hiding symbols, so the compiler can accept the constructed string.

3Infer and rebuild the string to avoid nested aliases

When a helper does multiple concatenations, use a conditional type to infer the inner portion and then reconstruct it:
\\\ts type FlattenLiteral<T extends string> = T extends \\${infer U}\` ? U : T;

type EventName<T extends string> = \handle\${Capitalize<FlattenLiteral<T>>}\;

// Even if T was itself a template literal type, FlattenLiteral narrows it to the inner union before the outer literal rebuilds it.
\\\ This trick lets the outer template literal operate on \U\`, which is a plain union instead of another template literal type.

4Generate derived unions explicitly instead of chaining literals

If you need both the prefixed value and the original literal, build them from the same union rather than reusing a literal alias:
\\\`ts
type States = "idle" | "active";

type Handler = \\${Capitalize<States>}Handler\;
\\\ Avoid writing \type StatesWithSuffix = \\${States}\; type Handler = \\${StatesWithSuffix}Handler\\ because the compiler sees a nested literal instead of a plain \States\` union.

Advanced notes

Template literal types became first-class in TypeScript 4.1 by allowing string concatenation at the type level. Each substitution placeholder must reduce to literal strings or number/boolean/nullish variants so the compiler can enumerate the resulting union statically. Nested template literal types, especially those derived from \keyof\ that still carry \symbol\ keys, are rejected because the compiler cannot guarantee symbol-free unions; see the open suggestion around \Template Literal Types derived from the type keys cannot be used as Indexed Access Types in generic contexts\ (microsoft/TypeScript#59909) for more background on why direct nesting is blocked. Flattening the inner union or exposing the primitive union directly keeps TypeScript's template literal reasoning sound and avoids the diagnostic.

Frequently asked questions

What does "Template literal type cannot contain template literal" mean?
The compiler produces "Template literal type cannot contain template literal" because it has to resolve the placeholder inside `... to a concrete string-like union. When the placeholder itself is still a template literal type (a union built from keyof T, ${string}`, or a helper alias), the compiler refuses to nest another template literal and raises the message to avoid cycles or symbol-induced unions.
How do I fix "Template literal type cannot contain template literal"?
TypeScript emits this error when a template literal placeholder resolves to another template literal type (often via keyof T or a mapped alias) and the compiler cannot treat it as a flattened string union. You can fix it by expanding the inner union, narrowing the placeholder to primitives, or using helper inference to rebuild the string.
What causes "Template literal type cannot contain template literal"?
You pass another template literal type (for example type Inner = ${string}``) directly into a template literal placeholder The helper alias still contains symbol keys (e.g. using keyof T without excluding symbols) and the compiler rejects the literal TypeScript cannot simplify the nested literal because it would require enumerating every permutation of the inner union
Is the "Template literal type cannot contain template literal" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading