TypeScript Union Types, Narrowing, and Generics
Introduction
Real data isn't always one type. Union types let a value be one of several types, narrowing lets the compiler work out which one you have at a given point, and generics let you write functions that work with many types while staying type-safe. This tutorial introduces all three.
Prerequisites
- Interfaces and type aliases
- Functions and arrays in TypeScript
Step-by-Step Guide
Step 1: Declare a union type
A union uses | to say a value can be any of several types. Literal types restrict a value to specific strings or numbers.
type Status = "loading" | "success" | "error";
let current: Status = "loading";
// current = "done";
// Error: Type '"done"' is not assignable to type 'Status'.Step 2: Narrow with type checks
Inside an if block that checks typeof, the compiler knows the narrowed type and allows operations specific to it.
function formatId(id: string | number): string {
if (typeof id === "string") {
return id.toUpperCase();
}
return id.toFixed(0);
}Step 3: Model variants with a discriminated union
Give each variant a shared literal property. Checking it narrows the object to exactly one variant.
type Result =
| { status: "success"; data: string }
| { status: "error"; message: string };
function handle(result: Result): string {
if (result.status === "success") {
return result.data;
}
return result.message;
}Step 4: Write a generic function
A type parameter such as T is a placeholder filled in by the caller's arguments, so the return type matches the input.
function firstItem<T>(items: T[]): T | undefined {
return items[0];
}
const n = firstItem([1, 2, 3]); // number | undefined
const s = firstItem(["a", "b"]); // string | undefinedFAQs
- What is type narrowing?
- Narrowing is the compiler refining a broad type to a more specific one based on checks like typeof, equality, or property tests, so you can safely use members that only exist on the narrower type.
- Why use generics instead of any?
- any turns off type checking. A generic keeps the relationship between input and output types, so you retain autocomplete and compile-time safety.
Summary
Unions model values that can take several forms, narrowing makes them safe to use, and generics keep reusable code type-safe. Discriminated unions are especially useful for results and state.
Comments
Log in or create a free account to join the discussion.