Interfaces & Type Aliases
Define object shapes with interfaces and type aliases, understand structural typing, union types, and when to use each
Knowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
TypeScript has two ways to name a type for an object shape: interfaces and type aliases. Both describe what properties an object must have.
Interface:
typescript interface User { id: number; name: string; email?: string; // optional property readonly createdAt: Date; // can't be reassigned after creation }
Type alias:
typescript type User = { id: number; name: string; email?: string; readonly createdAt: Date; };
Structural typing — TypeScript checks *shape*, not name. An object with the right properties satisfies a type even if it wasn't explicitly typed as that interface: ``typescript interface Point { x: number; y: number; } function printPoint(p: Point) { console.log(${p.x}, ${p.y}); } const myPoint = { x: 10, y: 20, z: 0 }; // extra property is fine printPoint(myPoint); // OK — has x and y
Extending interfaces:
typescript interface Animal { name: string; } interface Dog extends Animal { breed: string; } const rex: Dog = { name: 'Rex', breed: 'Labrador' };
Type alias intersection (equivalent to extends):
typescript type Animal = { name: string }; type Dog = Animal & { breed: string }; // intersection
Union types — a value that can be one of several types: ``typescript type StringOrNumber = string | number; type Status = 'active' | 'inactive' | 'pending'; // string literal union function format(val: StringOrNumber): string { return String(val); }
When to use which:
| | Interface | Type alias | |---|---|---| | Object shapes | ✅ Preferred | ✅ Works | | Union types | ❌ Can't do | ✅ Only option | | Extending | extends keyword | & intersection | | Declaration merging | ✅ (can add fields later) | ❌ |
Practical rule: use interface for object shapes (especially public APIs and React props), type for unions, primitives, and computed types.
Examples
Interface vs type alias for object shapes
For plain object shapes both work. Prefer `interface` for public APIs and class contracts; `type` when you need unions or complex computed types.
// Interface — preferred for object shapes
interface Product {
id: number;
name: string;
price: number;
inStock?: boolean; // optional
}
// Type alias — identical for basic object shapes
type ProductType = {
id: number;
name: string;
price: number;
inStock?: boolean;
};
// Both work identically here
function displayProduct(p: Product): string {
return `${p.name} - $${p.price}`;
}
const laptop: Product = { id: 1, name: 'Laptop', price: 999 };
console.log(displayProduct(laptop)); // "Laptop - $999"Union types and string literal unions
String literal unions are TypeScript's best pattern for fields with a fixed set of allowed values — much safer than bare `string`.
// Union — value is one of these types
type ID = string | number;
function getUser(id: ID): void {
if (typeof id === 'string') {
console.log('Looking up by username:', id);
} else {
console.log('Looking up by numeric id:', id);
}
}
getUser('alice'); // string branch
getUser(42); // number branch
// String literal union — the canonical pattern for status fields
type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
interface Order {
id: number;
status: OrderStatus;
}
const order: Order = { id: 1, status: 'shipped' };
// order.status = 'lost'; // Error: '"lost"' is not assignable to type 'OrderStatus'How well did you understand this?
Next in TypeScript
Typed Functions