TypeScript Fundamentals
Course 1 Β· Chapter 4 Β· Interfaces & Type Aliases
π€ Interfaces & Type Aliases
So far, you've written type annotations inline. As your code grows, repeating the same object shape becomes tedious and error-prone. This chapter introduces two ways to name and reuse types: type aliases and interfaces. Both solve the problemβknowing when to use each is the art.
π·οΈ Type Aliases
A type alias gives a name to any type using the type keyword. It's like assigning a type to a variable.
Basic Type Alias
type Age = number;
const myAge: Age = 30;
const yourAge: Age = "thirty";
Type Alias for Objects
The real power: reuse object shapes across your codebase:
type User = {
name: string;
email: string;
age: number;
isActive?: boolean;
};
const user1: User = { name: "Alice", email: "alice@example.com", age: 30 };
const user2: User = { name: "Bob", email: "bob@example.com", age: 25, isActive: true };
greet(user1);
greet(user2);
Union Type Aliases
Type aliases shine with unions β combining multiple types:
type ID = string | number;
type Status = "pending" | "active" | "inactive";
const userId: ID = 42;
const username: ID = "user123";
const currentStatus: Status = "active";
const badStatus: Status = "deleted";
π Interfaces
An interface is specifically for describing the shape of objects. It's similar to a type alias for objects, but with some key differences (which we'll explore).
Basic Interface
interface User {
name: string;
email: string;
age: number;
isActive?: boolean;
}
const user: User = { name: "Alice", email: "alice@example.com", age: 30 };
Notice the syntax difference: no `=` sign, no curly braces required.
Extending Interfaces
Interfaces can inherit from other interfaces using extends:
interface User {
name: string;
email: string;
}
interface AdminUser extends User {
role: "admin";
permissions: string[];
}
const admin: AdminUser = {
name: "Alice",
email: "alice@example.com",
role: "admin",
permissions: ["read", "write", "delete"]
};
Merging Interfaces
A unique power of interfaces: you can declare the same interface multiple times and they merge:
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = { name: "Alice", age: 30 };
This is powerful for adding properties to types across different files (think plugins).
βοΈ Type Aliases vs Interfaces
When to Use Each
Use Interfaces For:
- Object shapes (contracts)
- Classes to implement
- Code that merges types
- Public API definitions
Use Type Aliases For:
- Unions (string | number)
- Tuples ([string, number])
- Primitives (numbers, strings)
- Complex compositions
Key Differences
β
Interfaces can extend
interface Admin extends User { ... }
β
Interfaces merge
interface Window { x: number; }
interface Window { y: number; }
β
Types support unions
type Status = "on" | "off";
β
Types are more flexible
type Callback = () => void;
π§ Methods in Interfaces
Interfaces can describe methods (functions) as properties:
interface Logger {
log(message: string): void;
error(message: string): void;
}
const consoleLogger: Logger = {
log: (msg) => console.log(msg),
error: (msg) => console.error(msg)
};
π Readonly and Intersection Types
Readonly Properties
interface Config {
readonly apiKey: string;
port: number;
}
const config: Config = { apiKey: "secret", port: 3000 };
config.port = 4000;
config.apiKey = "newsecret";
Intersection Types (Preview)
Combine multiple types into one using &:
type Employee = User & { employeeId: number };
const emp: Employee = {
name: "Alice",
email: "alice@example.com",
age: 30,
employeeId: 12345
};
π» Coding Challenges
Challenge 1: Create a User Type Alias
Define a type alias for a user with:
- id (number)
- username (string)
- email (string)
- isVerified (boolean, optional)
Goal: Create the type alias and use it to define 2-3 user objects.
β Solution
Challenge 2: Extend an Interface
Create a base Person interface with name and age, then create an Employee interface that extends it and adds:
- employeeId (number)
- department (string)
Goal: Demonstrate interface inheritance.
β Solution
Challenge 3: Union Type for Status
Create a Status type that can only be one of: "pending", "approved", or "rejected". Then create a function that accepts this type and logs the status.
function handleStatus(status: Status): void {
}
Goal: Demonstrate union types with literals.
β Solution
π‘ Real-World Tip: Start with Interfaces
As a beginner, favor interfaces for object shapes and type aliases for everything else. Interfaces are slightly more limited, which forces you to write clearer, more maintainable code. You can always switch to a type alias if you need unions or other advanced features.
π― What's Next
Now that you can define contracts with types and interfaces, Chapter 5 introduces Classes & Object-Oriented TypeScript, where you'll see interfaces in action as contracts that classes implement.