Skip to content

Unveiling the Power of TypeScript Template Literal Types

Posted on:July 10, 2023

Table of contents

Open Table of contents

Understanding Template Literal Types

Template Literal Types extend the capabilities of string literal types by allowing developers to create types that are formed by concatenating strings. This introduces a level of dynamism and pattern matching that was not possible with traditional string literal types. The syntax for Template Literal Types involves using backticks (`) to define template literals and the ${} syntax for inserting expressions.

type Greeting = `Hello, ${string}!`;

In the above example, Greeting is a Template Literal Type that matches any string that starts with “Hello, ” and ends with an exclamation mark.

Basic Examples

Let’s start with some basic examples to illustrate the fundamental concepts of Template Literal Types.

Example 1: Concatenating Strings

type Concatenate<T extends string, U extends string> = `${T}${U}`;

type Result = Concatenate<"Hello", "World">; // Result is 'HelloWorld'

In this example, the Concatenate type takes two string literal types (T and U) and concatenates them using the template literal type syntax.

Example 2: String Manipulation

type UppercaseFirstChar<S extends string> = `${Uppercase<S[0]>}${S.substring(1)}`;

type CapitalizedGreeting = UppercaseFirstChar<'hello'>; // CapitalizedGreeting is 'Hello'

Here, the UppercaseFirstChar type transforms a string by capitalizing its first character.

Advanced Use Cases

Template Literal Types truly shine when used in more advanced scenarios, such as creating mapped types and enforcing specific patterns.

Example 3: Generating Object Keys

type GenerateKeys<T extends string> = {
  [K in T]: `${K}_key`;
};

type Keys = GenerateKeys<"one" | "two" | "three">;
// Keys is { one: 'one_key', two: 'two_key', three: 'three_key' }

In this example, the GenerateKeys type generates object keys based on the input string literal types.

Example 4.1: String Pattern Matching

type ExtractNumbers<S extends string> =
  S extends `${infer Prefix}${number}${infer Suffix}` ? number : never;

type ExtractedNumber = ExtractNumbers<"user123">; // ExtractedNumber is 123

Here, the ExtractNumbers type extracts a number from a string pattern.

Example 4.2: String Pattern Matching

type sizeValue = number | `${number}px` | `${number}em` | `${number}rem`;

const sizeSomething = (value: sizeValue) =>
  typeof value === "number" ? value + "%" : value;

sizeSomething(100); // 100%
sizeSomething("100px"); // 100px
sizeSomething("100vh"); // sizeSomething('100vh') // Error

Conclusion

TypeScript Template Literal Types provide a powerful mechanism for creating dynamic and pattern-based types, offering enhanced type safety and expressiveness. By leveraging template literal types, developers can craft more precise and flexible type definitions, leading to better code quality and maintainability. As TypeScript continues to evolve, Template Literal Types stand as a testament to the language’s commitment to empowering developers with advanced and expressive features.