Interfaces and Type Contracts
35 minInterfaces define the structure of objects and provide a way to define contracts for object shapes. They describe what properties an object should have and what types those properties should be. Interfaces are purely compile-time constructs—they don't exist at runtime, but they enable powerful type checking and IntelliSense support.
They can include optional properties (marked with `?`), readonly properties (marked with `readonly`), and function signatures. Optional properties allow flexibility in object shapes, while readonly properties prevent modification after initialization. Function signatures in interfaces define method contracts.
Interfaces can be extended and implemented by classes. Interface extension allows you to build on existing interfaces, creating hierarchies of types. Classes can implement multiple interfaces, enabling a form of multiple inheritance through interfaces. This provides flexibility while maintaining type safety.
TypeScript's structural typing means that if an object has all the properties an interface requires, it satisfies that interface, even if it wasn't explicitly declared to implement it. This is different from nominal typing in languages like Java, where types must be explicitly related.
Interfaces can also define index signatures for dynamic properties, call signatures for function types, and constructor signatures. These advanced features enable modeling complex JavaScript patterns in a type-safe way. Understanding these patterns is crucial for working with libraries and frameworks.
Best practices include using interfaces for object shapes, preferring interfaces over type aliases for extensibility, and using descriptive names that clearly indicate the interface's purpose. Interfaces should represent contracts that multiple implementations might satisfy.
Key Concepts
- Interfaces define contracts for object shapes and structures.
- Optional properties (?) allow flexibility in object shapes.
- readonly properties prevent modification after initialization.
- Interfaces can be extended to create type hierarchies.
- Classes can implement multiple interfaces for flexible design.
Learning Objectives
Master
- Creating interfaces for object shapes and contracts
- Using optional and readonly properties effectively
- Extending interfaces to build type hierarchies
- Implementing interfaces in classes
Develop
- Type design and contract thinking
- Understanding structural vs nominal typing
- Designing extensible type systems
Tips
- Use interfaces for object shapes that might have multiple implementations.
- Prefer interfaces over type aliases when you might need to extend them.
- Use optional properties (?) for properties that might not always be present.
- Mark properties as readonly when they shouldn't be modified after creation.
Common Pitfalls
- Creating interfaces that are too specific, limiting reusability.
- Not using optional properties when properties might be missing.
- Forgetting that interfaces are compile-time only—they don't exist at runtime.
- Overusing interfaces when simple type aliases would suffice.
Summary
- Interfaces define contracts for object shapes and structures.
- Optional and readonly properties provide flexibility and safety.
- Interfaces can be extended to create type hierarchies.
- Interfaces enable type-safe object modeling and IntelliSense support.
Exercise
Create an interface for a User object and use it in a function.
interface User {
id: number;
name: string;
email: string;
age?: number; // optional property
}
function createUser(user: User): User {
return user;
}
const newUser = createUser({
id: 1,
name: "John Doe",
email: "john@example.com"
});
console.log(newUser);
Exercise Tips
- Add readonly to id property: readonly id: number.
- Extend the interface: interface AdminUser extends User { role: string }.
- Create an interface with method signatures: interface Printable { print(): void }.
- Use index signatures for dynamic properties: [key: string]: any.