TypeScript Type Aliases
Understand type aliases, unions, and intersections to make your TypeScript code more expressive.
TL;DR
- 01Create reusable type names with the type keyword.
- 02Combine types using unions and intersections for flexibility.
- 03Lock values to literals for precise type safety.
Tips
- 01Use type aliases for unions and intersections, and use interfaces for object shapes you may want to extend later.
Warnings
- 01Type aliases cannot be merged like interfaces, so duplicate names will cause a compiler error.
Basic Syntax
- Declare a type alias using the
typekeyword and PascalCase naming.type User = { id: number; name: string; }; - Assign any valid type, including objects, primitives, or other type aliases.
type ID = number | string; - Use the alias anywhere you would normally write the full type expression.
const user: User = { id: 1, name: "Sam" }; - Type aliases can describe object shapes much like interfaces can.
- Keep aliases short and focused to make them easy to reuse.
Union Types
- Combine types with the pipe symbol for multiple allowed options.
type ID = string | number; const a: ID = "abc"; const b: ID = 42; - Use unions to allow a variable to hold values of different shapes.
- Narrow union types inside code using
typeoforinchecks.function format(value: string | number) { if (typeof value === "string") return value.trim(); return value.toFixed(2); } - Build status types from string literals for clear, restricted state.
type Status = "loading" | "success" | "error"; - Pass unions as function parameters to accept several valid input types.
Intersection Types
- Combine multiple types into one using the ampersand symbol between them.
type Named = { name: string }; type Aged = { age: number }; type Person = Named & Aged; - Intersections merge all properties from each type into a single shape.
const sam: Person = { name: "Sam", age: 30 }; - Use intersections to compose small types into larger object definitions.
- Conflicting property types in intersections create unusable
nevervalues. - Prefer intersections over interface extension when working with type aliases.
Literal Types
- Restrict a value to one exact string, number, or boolean literal.
type Direction = "up" | "down" | "left" | "right"; - Combine literal types with unions to create fixed sets of allowed values.
type Size = "sm" | "md" | "lg"; - Use literals for things like API methods, sizes, or status codes.
- Add
as constto objects to make all properties literal and readonly.const CONFIG = { mode: "prod" } as const; - Literal types catch typos that regular string types would silently allow.
Advanced Patterns
- Use generic type aliases for flexible, reusable type shapes.
type Box<T> = { value: T }; const n: Box<number> = { value: 42 }; - Build conditional types with the ternary-style syntax for advanced logic.
type IsString<T> = T extends string ? true : false; - Use mapped types to transform every key in another type.
type Optional<T> = { [K in keyof T]?: T[K] }; - Combine aliases with utility types to build reusable transformation patterns.
- Export type aliases from a shared file to keep types organized.
FAQ
Use a type alias when you need unions, intersections, or primitive types — things interfaces can't express. Prefer interfaces for object shapes that other types might extend or implement, since interfaces support declaration merging and are more idiomatic for OOP patterns.
You can't use the extends keyword directly on a type alias, but you can compose them using intersection types: type Admin = User & { role: 'admin' }. For true inheritance hierarchies, interfaces are more ergonomic since they natively support extends.
Declare it with the type keyword and separate each member with a pipe: type Status = 'active' | 'inactive' | 'pending'. You can union primitives, literals, or other type aliases together in a single declaration.
Unlike interfaces, type aliases do not support declaration merging — defining the same type name twice is a compiler error. Rename one of them or consolidate the definitions into a single type alias.
A union type (A | B) means a value can be either A or B, while an intersection type (A & B) means the value must satisfy both A and B simultaneously. Intersections are commonly used to merge object shapes, whereas unions model values that can take one of several forms.