0
0
Typescriptprogramming~15 mins

Template literal with unions in Typescript - Deep Dive

Choose your learning style9 modes available
Overview - Template literal with unions
What is it?
Template literal types in TypeScript let you create new string types by combining other string types or literals. When combined with union types, you can build flexible and precise string patterns that represent many possible values. This helps TypeScript understand exactly what strings are allowed in your code. It’s like creating a custom dictionary of allowed words made from smaller word parts.
Why it matters
Without template literal types combined with unions, you would have to list every possible string manually or lose type safety by using plain strings. This makes your code less safe and harder to maintain. Using these features helps catch mistakes early, improves code clarity, and enables powerful autocomplete suggestions in editors. It makes your programs smarter about strings, preventing bugs and saving time.
Where it fits
Before learning this, you should understand basic TypeScript types, string literals, and union types. After this, you can explore advanced type manipulations like conditional types, mapped types, and recursive types to build even more powerful type systems.
Mental Model
Core Idea
Template literal types with unions let you build complex string types by mixing fixed parts and multiple options, like assembling words from interchangeable pieces.
Think of it like...
Imagine you have a box of colored letter tiles and a list of possible prefixes and suffixes. You can create many different words by choosing one prefix, one middle part, and one suffix. Template literal types with unions are like picking tiles from different sets to form all valid words you want.
┌───────────────┐
│ Prefix Union  │  (e.g., 'get' | 'set')
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Middle String │  (e.g., 'Name' | 'Age')
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Suffix Union  │  (e.g., 'Value' | 'Count')
└───────────────┘

Combined type: `${Prefix Union}${Middle String}${Suffix Union}`

Example values: 'getNameValue', 'setAgeCount', etc.
Build-Up - 7 Steps
1
FoundationUnderstanding string literal types
🤔
Concept: Learn what string literal types are and how they represent exact strings in TypeScript.
In TypeScript, you can create a type that only allows a specific string, like this: ```typescript type Direction = 'left' | 'right'; ``` This means a variable of type Direction can only be 'left' or 'right'. It’s like a label that restricts values to certain words.
Result
Variables of type Direction accept only 'left' or 'right', and TypeScript will give errors for other strings.
Understanding string literal types is key because template literal types build on these exact string values to create more complex patterns.
2
FoundationBasics of union types
🤔
Concept: Union types let you combine multiple types into one, meaning a value can be any one of those types.
For example: ```typescript type Status = 'success' | 'error' | 'loading'; ``` Here, Status can be one of three strings. This is useful to represent limited options clearly.
Result
TypeScript enforces that variables of type Status only hold one of the three allowed strings.
Knowing union types helps you see how multiple options can be combined, which is essential for building template literal unions.
3
IntermediateCreating template literal types
🤔
Concept: Template literal types let you combine string literals and unions into new string types using backticks and placeholders.
You can write: ```typescript type Event = `on${'Click' | 'Hover'}`; ``` This means Event can be 'onClick' or 'onHover'. It’s like writing a pattern that matches specific strings.
Result
TypeScript knows Event is exactly 'onClick' or 'onHover', and will error on other strings.
This shows how template literals let you build new string types from smaller parts, making your types more expressive.
4
IntermediateCombining multiple unions in templates
🤔Before reading on: do you think combining two unions in a template literal creates all possible combinations or just some?
Concept: When you use multiple unions inside a template literal, TypeScript creates all possible combinations of those options.
Example: ```typescript type Action = 'get' | 'set'; type Property = 'Name' | 'Age'; type Method = `${Action}${Property}`; ``` Method can be 'getName', 'getAge', 'setName', or 'setAge'. TypeScript combines every option from Action with every option from Property.
Result
The Method type includes all four string combinations, giving precise control over allowed strings.
Knowing that unions expand to all combinations helps you predict and control the exact strings your types allow.
5
IntermediateUsing unions with template literals and other types
🤔Before reading on: can template literal types combine with non-string unions like numbers or booleans directly?
Concept: Template literal types work only with string or number literal types, but numbers are converted to strings automatically in templates.
Example: ```typescript type Size = 'Small' | 'Large'; type Quantity = 1 | 2; type Label = `${Size}${Quantity}`; ``` Label can be 'Small1', 'Small2', 'Large1', or 'Large2'. Numbers become strings inside the template.
Result
TypeScript treats number literals as strings in template literals, allowing mixed unions of strings and numbers.
Understanding this conversion prevents confusion and lets you mix numeric and string options smoothly.
6
AdvancedNesting template literals with unions
🤔Before reading on: do nested template literals with unions multiply combinations or flatten them?
Concept: You can nest template literals inside unions to build very complex string types, and TypeScript expands all combinations recursively.
Example: ```typescript type Prefix = 'get' | 'set'; type Property = 'Name' | 'Age'; type Suffix = 'Value' | 'Count'; type Method = `${Prefix}${Property}${Suffix}`; ``` Method includes all 8 combinations like 'getNameValue', 'setAgeCount', etc.
Result
TypeScript generates every possible string from all union options in nested templates.
Knowing how nesting multiplies combinations helps you design precise and scalable string types without listing every option manually.
7
ExpertTemplate literal unions in conditional types
🤔Before reading on: can template literal unions be used inside conditional types to transform or filter string types?
Concept: Template literal types combined with unions can be used inside conditional types to create powerful type transformations and filters based on string patterns.
Example: ```typescript type Event = 'onClick' | 'onHover' | 'offClick'; type OnEvent = T extends `on${string}` ? T : never; type OnlyOnEvents = OnEvent; // 'onClick' | 'onHover' ``` This filters Event to only those starting with 'on'.
Result
You can create types that pick or change string unions based on patterns, enabling advanced type logic.
Understanding this unlocks expert-level type programming, letting you build smart APIs and validations at compile time.
Under the Hood
TypeScript’s compiler processes template literal types by expanding all union options inside the template strings at compile time. It generates a union of all possible string combinations represented by the template. This expansion happens recursively for nested templates. The compiler treats number literals as strings when inside templates. Conditional types can then operate on these expanded unions to filter or transform them. This all happens purely in the type system, with no runtime cost.
Why designed this way?
Template literal types were introduced to bring the power of string interpolation from JavaScript into the type system, enabling more precise and expressive types. Unions allow representing multiple options compactly. Combining them lets developers avoid repetitive manual string unions and catch errors early. The design balances expressiveness with compiler performance by expanding unions at compile time rather than runtime.
┌─────────────────────────────┐
│ Union Types (e.g., 'get' | 'set') │
└───────────────┬─────────────┘
                │
                ▼
┌─────────────────────────────┐
│ Template Literal Type        │
│ (e.g., `${Action}${Property}`) │
└───────────────┬─────────────┘
                │ Expands all combinations
                ▼
┌─────────────────────────────┐
│ Expanded Union of Strings    │
│ ('getName', 'setAge', ...)  │
└─────────────────────────────┘
                │
                ▼
┌─────────────────────────────┐
│ Conditional Types (optional) │
│ Filter or transform strings  │
└─────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does a template literal with unions create only some combinations or all possible combinations? Commit to your answer.
Common Belief:Template literals with unions only create some combinations, not all possible ones.
Tap to reveal reality
Reality:They create all possible combinations by expanding every option in each union inside the template.
Why it matters:If you expect only some combinations, you might miss allowed strings or get unexpected errors when using the type.
Quick: Can template literal types accept any string at runtime? Commit to yes or no.
Common Belief:Template literal types restrict runtime strings strictly to the defined patterns.
Tap to reveal reality
Reality:Template literal types only exist at compile time for type checking; at runtime, strings are normal strings without restrictions.
Why it matters:Relying on template literal types for runtime validation leads to bugs because they don’t enforce constraints during execution.
Quick: Can you use any type inside template literals, like objects or booleans? Commit to yes or no.
Common Belief:You can use any type inside template literals, including objects or booleans.
Tap to reveal reality
Reality:Only string and number literal types can be used inside template literals; other types cause errors.
Why it matters:Trying to use unsupported types causes confusing compiler errors and blocks type checking.
Quick: Does nesting template literals flatten combinations or multiply them? Commit to your answer.
Common Belief:Nesting template literals flattens combinations into fewer options.
Tap to reveal reality
Reality:Nesting multiplies combinations, creating a union of all possible nested string combinations.
Why it matters:Misunderstanding this can lead to unexpected large unions and slow compilation or incorrect type expectations.
Expert Zone
1
Template literal types can be combined with conditional types to create powerful pattern matching and filtering at compile time.
2
Excessive nesting or very large unions can cause TypeScript compiler performance issues, so balancing complexity is important.
3
Template literal types do not exist at runtime, so runtime validation requires separate checks or libraries.
When NOT to use
Avoid using template literal unions when the number of combinations grows exponentially and hurts compiler performance. For dynamic or user-generated strings, prefer runtime validation libraries instead of relying solely on types.
Production Patterns
In real-world code, template literal unions are used for defining event names, CSS class names, API endpoint paths, and other string patterns where strict control improves safety and developer experience. They often combine with mapped types and conditional types to build flexible yet precise type-safe APIs.
Connections
Regular expressions
Both define patterns for strings but in different domains: template literal types at compile time, regex at runtime.
Understanding template literal types helps appreciate how pattern matching can be done statically in types, complementing runtime regex.
Algebraic data types (ADTs)
Template literal unions are a form of sum types (unions) combined with product types (concatenation), similar to ADTs in functional programming.
Recognizing this connection reveals how type systems model complex data by combining simple options, bridging string types and algebraic structures.
Natural language morphology
Building strings from unions of prefixes, roots, and suffixes mirrors how words form in languages by combining morphemes.
Seeing template literal unions like word formation deepens understanding of how complex types can be composed from smaller meaningful parts.
Common Pitfalls
#1Expecting template literal types to enforce runtime string validation.
Wrong approach:function handleEvent(event: string) { if (event === 'onClick' || event === 'onHover') { // ... } } // Using type: type Event = `on${'Click' | 'Hover'}`; // But no runtime check is done automatically.
Correct approach:type Event = `on${'Click' | 'Hover'}`; function handleEvent(event: Event) { // TypeScript ensures only valid events at compile time } // For runtime validation, add explicit checks or use libraries.
Root cause:Confusing compile-time type checks with runtime behavior leads to missing validation and potential bugs.
#2Using non-string or non-number types inside template literals.
Wrong approach:type Invalid = `${boolean}`; // Error const val: Invalid = 'true';
Correct approach:type Valid = `${'true' | 'false'}`; const val: Valid = 'true';
Root cause:Misunderstanding that template literals only accept string or number literal types causes compiler errors.
#3Assuming template literal unions create only some combinations, not all.
Wrong approach:type A = 'x' | 'y'; type B = '1' | '2'; type AB = `${A}${B}`; // Expecting only 'x1' and 'y2', but actually includes 'x2' and 'y1'
Correct approach:type AB = `${A}${B}`; // Includes all combinations: 'x1', 'x2', 'y1', 'y2'
Root cause:Not realizing unions expand fully leads to incorrect assumptions about allowed strings.
Key Takeaways
Template literal types with unions let you build precise string types by combining fixed parts and multiple options.
They expand all combinations of union members inside the template, creating comprehensive sets of allowed strings.
Only string and number literal types can be used inside template literals; other types cause errors.
These types exist only at compile time and do not enforce runtime validation by themselves.
Combining template literals with conditional types unlocks powerful compile-time string pattern matching and filtering.