implements: реализация интерфейсов
Ключевое слово
implementsв TypeScript указывает, что класс обязуется реализовать все члены интерфейса; компилятор проверяет соответствие и выдаёт ошибку при отсутствии или несовместимости любого из них.
Зачем нужно
implements позволяет отделить контракт (интерфейс) от реализации (класс). Это основа принципов SOLID (особенно ISP и DIP): код зависит от интерфейсов, а не от конкретных классов, что упрощает замену реализаций и тестирование через mock.
Где используется
- Repository, Service, Gateway паттерны
- Dependency Injection — классы реализуют интерфейсы зависимостей
- Тестирование — mock-классы реализуют те же интерфейсы
- Плагин-системы — каждый плагин реализует общий интерфейс
- Стратегии и адаптеры
Основной контент
Базовый синтаксис
interface Greeter {
greet(name: string): string;
farewell(name: string): string;
}
class EnglishGreeter implements Greeter {
greet(name: string): string {
return `Hello, ${name}!`;
}
farewell(name: string): string {
return `Goodbye, ${name}!`;
}
}
class RussianGreeter implements Greeter {
greet(name: string): string {
return `Привет, ${name}!`;
}
farewell(name: string): string {
return `Пока, ${name}!`;
}
}
// Использование через интерфейс — не зависим от конкретного класса
function greetUser(greeter: Greeter, user: string): void {
console.log(greeter.greet(user));
}
Реализация нескольких интерфейсов
interface Serializable {
serialize: string;
}
interface Validatable {
validate: boolean;
}
class Order implements Serializable, Validatable {
constructor(
private id: string,
private items: string,
private total: number,
) {}
serialize: string {
return JSON.stringify({ id: this.id, items: this.items, total: this.total });
}
validate: boolean {
return this.items.length > 0 && this.total > 0;
}
}
Repository паттерн
interface UserRepository {
findById(id: string): Promise<User | null>;
findAll: Promise<User>;
save(user: User): Promise<User>;
delete(id: string): Promise<void>;
}
// Реальная реализация
class PostgresUserRepository implements UserRepository {
async findById(id: string) { /* SQL запрос */ return null; }
async findAll { return ; }
async save(user: User) { return user; }
async delete(id: string) { /* ... */ }
}
// Mock для тестов
class InMemoryUserRepository implements UserRepository {
private users = new Map<string, User>;
async findById(id: string) { return this.users.get(id) ?? null; }
async findAll { return [...this.users.values()]; }
async save(user: User) { this.users.set(user.id, user); return user; }
async delete(id: string) { this.users.delete(id); }
}
implements vs extends
// extends — наследование, получаем реализацию родителя
class Dog extends Animal { /* ... */ }
// implements — только контракт, без наследования реализации
class Labrador implements Animal { /* нужно реализовать всё */ }
// Можно комбинировать
class SpecialDog extends Dog implements Serializable {
serialize: string { return JSON.stringify(this); }
}
implements с generic интерфейсом
interface Repository<T> {
findById(id: string): Promise<T | null>;
save(entity: T): Promise<T>;
}
class OrderRepository implements Repository<Order> {
async findById(id: string): Promise<Order | null> { return null; }
async save(order: Order): Promise<Order> { return order; }
}
Частые ошибки
- Пропустить хотя бы один метод интерфейса — компилятор выдаст ошибку с указанием отсутствующего члена.
- Несовместимая сигнатура — метод
greet(n: number)не реализуетgreet(n: string)из интерфейса. implementsне влияет на совместимость в рантайме — TypeScript использует структурную типизацию;instanceofне проверяетimplements.- Путать
implementsиextends—implementsберёт только контракт,extends— реализацию; нельзяimplementsот класса безabstract.
Связанные темы
- interface -- объявление и использование
- abstract классы
- Generic интерфейсы и классы
- Расширение интерфейсов -- extends
- _MOC TypeScript