2.1 Наследование интерфейсов
Одна из важнейших возможностей интерфейсов — их расширение и объединение, что позволяет создавать более гибкие и многократно используемые типы. Ниже мы рассмотрим, как наследование и объединение интерфейсов помогают создавать сложные типы и поддерживать DRY (Don't Repeat Yourself) принцип в TypeScript.
Наследование интерфейсов позволяет одному интерфейсу наследовать свойства и методы другого интерфейса. Это полезно для создания иерархий типов и повторного использования типовых описаний.
Синтаксис наследования интерфейсов
Для наследования интерфейса используется ключевое слово extends:
interface ChildInterface extends ParentInterface {
...
}
Пример:
"use strict";
let employee = {
name: 'Alice',
age: 30,
employeeId: 12345
};
console.log(employee);
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: number;
}
let employee: Employee = {
name: 'Alice',
age: 30,
employeeId: 12345
};
console.log(employee);
В этом примере интерфейс Employee наследует свойства name и age от интерфейса Person и добавляет собственное свойство employeeId. Объект employee должен соответствовать обоим интерфейсам.
Наследование нескольких интерфейсов
Интерфейс в TypeScript может наследовать сразу несколько интерфейсов, объединяя их свойства и методы:
"use strict";
let employee = {
name: 'Bob',
age: 40,
email: 'bob@example.com',
phone: '555-1234',
employeeId: 67890
};
console.log(employee);
interface Person {
name: string;
age: number;
}
interface Contact {
email: string;
phone: string;
}
interface Employee extends Person, Contact {
employeeId: number;
}
let employee: Employee = {
name: 'Bob',
age: 40,
email: 'bob@example.com',
phone: '555-1234',
employeeId: 67890
};
console.log(employee);
В этом примере интерфейс Employee наследует свойства name и age от интерфейса Person, а также свойства email и phone от интерфейса Contact. Объект employee должен включать все эти свойства.
Примеры использования наследования интерфейсов
Наследование интерфейсов полезно при создании типовых иерархий для сложных объектов. Рассмотрим пример использования интерфейсов для описания системы управления персоналом:
"use strict";
let employee = {
name: 'Charlie',
age: 35,
street: '123 Elm St',
city: 'Somewhere',
zipCode: '12345',
email: 'charlie@example.com',
phone: '555-5678',
employeeId: 13579,
position: 'Developer'
};
console.log(employee);
interface Person {
name: string;
age: number;
}
interface Address {
street: string;
city: string;
zipCode: string;
}
interface Contact extends Address {
email: string;
phone: string;
}
interface Employee extends Person, Contact {
employeeId: number;
position: string;
}
let employee: Employee = {
name: 'Charlie',
age: 35,
street: '123 Elm St',
city: 'Somewhere',
zipCode: '12345',
email: 'charlie@example.com',
phone: '555-5678',
employeeId: 13579,
position: 'Developer'
};
console.log(employee);
В этом примере интерфейс Employee наследует свойства от Person и Contact, который в свою очередь наследует свойства от Address. Это позволяет описать полный набор свойств для объекта employee.
2.2 Объединение интерфейсов
TypeScript поддерживает возможность объединения интерфейсов с одинаковыми именами. Это полезно, когда необходимо добавить новые свойства или методы к существующему интерфейсу, не изменяя его исходное определение. Объединение интерфейсов происходит автоматически, если в одном или в разных файлах определены интерфейсы с одинаковыми именами.
Синтаксис объединения интерфейсов
Для объединения интерфейсов достаточно объявить несколько интерфейсов с одним и тем же именем:
"use strict";
let box = {
width: 100,
height: 200,
color: 'red'
};
console.log(box);
interface Box {
width: number;
height: number;
}
interface Box {
color: string;
}
let box: Box = {
width: 100,
height: 200,
color: 'red'
};
console.log(box);
Здесь два интерфейса Box объединяются, и объект box должен соответствовать всем объединенным свойствам.
Примеры использования объединения интерфейсов
Объединение интерфейсов полезно для добавления новых свойств к существующим интерфейсам, особенно при расширении функциональности библиотек или API:
"use strict";
let myWindow = {
title: 'Main Window',
width: 800,
height: 600,
setPosition(x, y) {
console.log(`Window moved to position (${x}, ${y})`);
}
};
console.log(myWindow);
myWindow.setPosition(100, 200);
interface Window {
title: string;
}
interface Window {
width: number;
height: number;
}
interface Window {
setPosition(x: number, y: number): void;
}
let myWindow: Window = {
title: 'Main Window',
width: 800,
height: 600,
setPosition(x, y) {
console.log(`Window moved to position (${x}, ${y})`);
}
};
console.log(myWindow);
myWindow.setPosition(100, 200);
В этом примере интерфейс Window объединяет свойства и метод из трех объявлений. Объект myWindow должен включать все объединенные свойства и метод.
2.3 Расширение и объединение интерфейсов в реальных проектах
Рассмотрим несколько примеров использования расширения и объединения интерфейсов в реальных проектах.
Пример 1: Расширение интерфейсов для описания моделей данных
В приложениях со сложными моделями данных расширение интерфейсов позволяет описывать связанные сущности:
"use strict";
let user = {
id: 1,
createdAt: new Date(),
updatedAt: new Date(),
name: 'Alice',
email: 'alice@example.com'
};
let product = {
id: 101,
createdAt: new Date(),
updatedAt: new Date(),
name: 'Laptop',
price: 1200
};
console.log(user, product);
interface BaseEntity {
id: number;
createdAt: Date;
updatedAt: Date;
}
interface User extends BaseEntity {
name: string;
email: string;
}
interface Product extends BaseEntity {
name: string;
price: number;
description?: string;
}
let user: User = {
id: 1,
createdAt: new Date(),
updatedAt: new Date(),
name: 'Alice',
email: 'alice@example.com'
};
let product: Product = {
id: 101,
createdAt: new Date(),
updatedAt: new Date(),
name: 'Laptop',
price: 1200
};
console.log(user, product);
Здесь интерфейсы User и Product наследуют общие свойства от интерфейса BaseEntity, что упрощает управление общими данными.
Пример 2: Объединение интерфейсов для расширения библиотек
Объединение интерфейсов полезно для расширения функциональности существующих библиотек без изменения их исходного кода:
"use strict";
let $element = {
fadeIn(duration) {
console.log(`Element fades in over ${duration}ms`);
},
fadeOut(duration) {
console.log(`Element fades out over ${duration}ms`);
}
};
$element.fadeIn(400); // Element fades in over 400ms
$element.fadeOut(300); // Element fades out over 300ms
interface JQuery {
fadeIn(duration: number): void;
}
interface JQuery {
fadeOut(duration: number): void;
}
let $element: JQuery = {
fadeIn(duration) {
console.log(`Element fades in over ${duration}ms`);
},
fadeOut(duration) {
console.log(`Element fades out over ${duration}ms`);
}
};
$element.fadeIn(400); // Element fades in over 400ms
$element.fadeOut(300); // Element fades out over 300ms
Интерфейс JQuery объединяет методы fadeIn и fadeOut, добавляя новые возможности к объекту $element.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ