Skip to main content

TS Ep 48: String Manipulation Utilities

Rachmat Hidayat
Author
Rachmat Hidayat
Learn & sharing insights on TypeScript, Go, Kubernetes, DevOps, DevSecOps, SRE, Platform Engineering, AI/ML Engineering, and MLOps.
typescript - This article is part of a series.
Part 48: This Article
If your backend database uses snake_case but your frontend React application uses camelCase, you don’t need to manually map dozens of properties. You can use TypeScript’s built-in string utilities to transform the types automatically!

1. The Four “Intrinsic” Utilities
#

TypeScript includes four built-in string manipulation utilities.

Unlike other utilities (like Partial or Exclude) which are written in normal TypeScript code using mapped types or conditionals, these four utilities are intrinsic. This means they are hardcoded directly into the TypeScript compiler (using C++) for maximum performance.

  1. Uppercase<StringType>
  2. Lowercase<StringType>
  3. Capitalize<StringType>
  4. Uncapitalize<StringType>
type Role = "adminUser";

type Upper = Uppercase<Role>;       // "ADMINUSER"
type Lower = Lowercase<"API_KEY">;  // "api_key"
type Cap   = Capitalize<Role>;      // "AdminUser"
type Uncap = Uncapitalize<"Admin">; // "admin"

2. Combining with Template Literals
#

These utilities are almost never used in isolation. Their true power unlocks when you interpolate them into Template Literal Types (from Episode 47).

Imagine a generic state machine. You have a union of state names, and you want to generate a union of string literals representing the transition action for each state (e.g., goTo[State]).

type States = "idle" | "loading" | "success" | "error";

// 🟢 Capitalize the state name, and prefix it with "goTo"
type TransitionActions = `goTo${Capitalize<States>}`;

/* Inferred Union: 
  | "goToIdle" 
  | "goToLoading" 
  | "goToSuccess" 
  | "goToError"
*/

3. Real-World Architecture: Event Emitters
#

The most common real-world application of String Manipulation Utilities is building strictly typed Event Emitters or component props.

Suppose you have an interface detailing the payloads for different events. You want to generate a Props interface for a UI component that demands an on[EventName] handler for every event.

We can achieve this by combining Mapped Types (Episode 38), Key Remapping with as (Episode 40), and Capitalize:

// 1. The Single Source of Truth
interface EventPayloads {
  click: { x: number; y: number };
  hover: { elementId: string };
  scroll: { offset: number };
}

// 2. The Type-Level Transformer
type EventHandlers<T> = {
  // Iterate over every key K in the interface.
  // Remap the key to be: on + Capitalized(K).
  // Set the value to be a callback accepting the original payload (T[K]).
  [K in keyof T as `on${Capitalize<K & string>}`]: (event: T[K]) => void;
};

// 3. The Result
type ComponentProps = EventHandlers<EventPayloads>;

/* 
ComponentProps is strictly inferred as:
{
  onClick: (event: { x: number; y: number }) => void;
  onHover: (event: { elementId: string }) => void;
  onScroll: (event: { offset: number }) => void;
}
*/

The Architectural Benefit
#

If another developer adds keyboard: { key: string } to the EventPayloads interface, the ComponentProps type will instantly and automatically require an onKeyboard handler. Your UI contracts are perfectly synchronized with your data layer.


Summary & Next Steps
#

In this episode:

  • We introduced the four intrinsic compiler string utilities: Uppercase, Lowercase, Capitalize, and Uncapitalize.
  • We combined them with Template Literals to dynamically generate string variants.
  • We constructed a fully automated Event Handler generator using Mapped Types and Key Remapping (as).

In Episode 49: Recursive Types, we will dive into one of the most conceptually challenging areas of Type Space: types that call themselves to drill down into infinitely nested objects!

typescript - This article is part of a series.
Part 48: This Article