🌱BeginnerObject Types & Interfaces
Type Aliases
The type keyword naming complex types, union/intersection aliases, and when to choose type vs interface.
Overview
The `type` keyword creates a **type alias** a name for any type expression. Unlike `interface` which only describes object shapes, `type` can alias any type: primitives, unions, intersections, tuples, function signatures, conditional types, and more.
`type` and `interface` overlap heavily for describing object shapes. The key differences:
- **`type`**: can alias any type (unions, primitives, tuples, mapped types); cannot be re-opened (declaration merging)
- **`interface`**: only object shapes and function signatures; supports declaration merging (useful for extending global types)
The community convention: use `interface` for object shapes that represent APIs or class contracts; use `type` for unions, intersections, tuples, and any complex type expression.
Key Points
- •`type Alias = ExistingType` gives a name to any type
- •`type` can alias unions: `type ID = string | number`
- •`type` can alias intersections: `type Admin = User & { permissions: string[] }`
- •`type` can alias tuples, function signatures, and even primitives
- •`interface` vs `type`: prefer `interface` for extendable object shapes, `type` for complex/computed types
- •`type` does NOT support declaration merging (unlike `interface`)
- •Both are erased at compile time zero runtime overhead
Examples
Type aliases for primitives and unions
// Aliases for primitive types
type Username = string;
type UserId = number | string; // union
type Nullable<T> = T | null; // generic alias
const id: UserId = "user-123";
const id2: UserId = 42;
// Union types one of several options
type Status = "pending" | "active" | "inactive" | "deleted";
type Result = "success" | "error";
function setStatus(status: Status): void {
console.log(`Status: ${status}`);
}
setStatus("active");
// setStatus("unknown"); // Error!
// Nullable helper
type MaybeString = Nullable<string>;
const val: MaybeString = null; // okObject type aliases and intersections
// Object shape as type alias
type Point = {
x: number;
y: number;
};
type Point3D = Point & { z: number }; // intersection
const p: Point = { x: 1, y: 2 };
const p3: Point3D = { x: 1, y: 2, z: 3 };
// Intersection for mixins
type Timestamped = {
createdAt: Date;
updatedAt: Date;
};
type User = {
id: number;
name: string;
email: string;
};
type UserRecord = User & Timestamped;
const user: UserRecord = {
id: 1,
name: "Alice",
email: "alice@example.com",
createdAt: new Date(),
updatedAt: new Date(),
};Function type aliases
// Function signature as type alias
type Predicate<T> = (value: T) => boolean;
type Transformer<T, U> = (value: T) => U;
type Callback = (error: Error | null, result?: string) => void;
const isPositive: Predicate<number> = n => n > 0;
const stringify: Transformer<number, string> = n => String(n);
console.log(isPositive(5)); // true
console.log(isPositive(-1)); // false
console.log(stringify(42)); // "42"
// Discriminated union with type aliases
type Square = { kind: "square"; side: number };
type Circle = { kind: "circle"; radius: number };
type Triangle = { kind: "triangle"; base: number; height: number };
type Shape = Square | Circle | Triangle;
function area(s: Shape): number {
switch (s.kind) {
case "square": return s.side ** 2;
case "circle": return Math.PI * s.radius ** 2;
case "triangle": return 0.5 * s.base * s.height;
}
}
console.log(area({ kind: "square", side: 4 })); // 16
console.log(area({ kind: "circle", radius: 3 })); // 28.27...
console.log(area({ kind: "triangle", base: 6, height: 4 })); // 12Common Mistakes
- Using `type` when `interface` would be clearer for object shapes both work, but `interface` communicates "this is an object contract"
- Trying to merge type aliases unlike interfaces, redeclaring the same `type` is an error
- Forgetting that intersection (`&`) doesn't deeply merge conflicting property types `{ a: number } & { a: string }` gives `a: never`
Note
A simple mental model: use `interface` when you're describing the shape of a class instance or API response object (especially if you might extend it later). Use `type` for everything else unions, intersections, tuples, function signatures, and utility types.
Exercises
Write TypeScript code to solve each exercise. Click Run to compile and execute it right here, then mark as done.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4