TypeScript Aliases and Interfaces
Type aliases and interfaces are two ways to name and reuse type shapes in TypeScript, and understanding their differences helps you choose the right tool for each situation.
Declaring a Type Alias
A type alias, declared with the type keyword, gives a name to any type: an object shape, a union, a tuple, or even a primitive. It is the more general and flexible of the two mechanisms.
Type Alias Basics
type UserId = string;
type Point = {
x: number;
y: number;
};
type Status = "active" | "inactive" | "banned";
const id: UserId = "user_123";
const origin: Point = { x: 0, y: 0 };
const status: Status = "active";Declaring an Interface
An interface, declared with the interface keyword, describes the shape of an object or a class contract. It reads similarly to a type alias for object shapes but is limited to describing object-like structures.
Interface Basics
interface Point3D {
x: number;
y: number;
z: number;
}
function distanceFromOrigin(point: Point3D): number {
return Math.sqrt(point.x ** 2 + point.y ** 2 + point.z ** 2);
}
const p: Point3D = { x: 3, y: 4, z: 0 };
console.log(distanceFromOrigin(p)); // 5Extending and Merging
Interfaces can be extended with the extends keyword and support declaration merging, meaning two interfaces with the same name in the same scope automatically combine their members. Type aliases use intersections (&) to combine shapes instead, and cannot be merged by re-declaring them.
Extending an Interface vs Intersecting a Type
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
type AnimalT = { name: string };
type DogT = AnimalT & { breed: string };
const dog: Dog = { name: "Rex", breed: "Labrador" };
const dogT: DogT = { name: "Milo", breed: "Beagle" };type vs interface
Realistic Use Case: Public API Shapes
A common convention is to use interfaces for the public shapes of objects and classes that consumers of a library might extend, and type aliases for unions, tuples, and one-off compositions.
Combining Both in Practice
interface ApiError {
code: number;
message: string;
}
type ApiResult<T> = { success: true; data: T } | { success: false; error: ApiError };
function handleResult(result: ApiResult<string>) {
if (result.success) {
console.log("Data:", result.data);
} else {
console.log("Error:", result.error.message);
}
}- Use interface for object shapes that libraries or consumers might extend or merge.
- Use type for unions, tuples, mapped types, and other non-object compositions.
- Both support generics and can be used interchangeably for plain object shapes.
- Neither one has a runtime representation — both disappear when compiled to JavaScript.
Exercise: TypeScript Aliases & Interfaces
Which statement about type aliases is accurate?