1.1 Основы интерфейсов
Интерфейсы в TypeScript играют очень важную роль в обеспечении статической типизации и структурной целостности кода. Они позволяют определить формы объектов, задавая контракты, которые должны выполнять эти объекты. Интерфейсы помогают разработчикам создавать более предсказуемый и надежный код, улучшая читаемость и поддержку.
Интерфейс в TypeScript представляет собой контракт, который описывает структуру объекта. Интерфейсы могут включать свойства и методы, которые объект должен реализовать. Интерфейсы не содержат реализации методов и используются только для описания формы объекта.
Объявление интерфейса
Для объявления интерфейса используется ключевое слово interface, за которым следует имя интерфейса и его определение.
Пример:
interface User {
name: string;
age: number;
isAdmin: boolean;
}
let user: User = {
name: 'Alice',
age: 30,
isAdmin: true
};
В этом примере интерфейс User описывает объект с тремя свойствами: name, age и isAdmin. Объект user соответствует этому интерфейсу.
Опциональные свойства
Интерфейсы позволяют задавать опциональные свойства с помощью символа "?" после имени свойства. Опциональные свойства могут присутствовать в объекте, но их значение может отсутствовать.
Пример:
interface User {
name: string;
age: number;
isAdmin?: boolean; // Опциональное свойство
}
let user1: User = {
name: 'Bob',
age: 40
};
let user2: User = {
name: 'Charlie',
age: 35,
isAdmin: true
};
В этом примере свойство isAdmin опционально. Объект user1 не содержит это свойство, в то время как объект user2 содержит.
Readonly свойства
Интерфейсы могут включать свойства, которые не могут быть изменены после инициализации. Для этого используется ключевое слово readonly.
Пример:
interface User {
readonly id: number;
name: string;
age: number;
}
let user: User = {
id: 1,
name: 'Alice',
age: 30
};
user.age = 31; // Допустимо
user.id = 2; // Ошибка компиляции: Cannot assign to 'id' because it is a read-only property.
В этом примере свойство id неизменяемое, и попытка изменить его значение приведет к ошибке компиляции.
Методы в интерфейсах
Интерфейсы могут включать описание методов, которые должны быть реализованы объектами, соответствующими этому интерфейсу.
Пример:
"use strict";
let user = {
name: 'Alice',
age: 30,
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
user.greet(); // Вывод: Hello, my name is Alice
interface User {
name: string;
age: number;
greet(): void;
}
let user: User = {
name: 'Alice',
age: 30,
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
user.greet(); // Вывод: Hello, my name is Alice
В этом примере интерфейс User включает метод greet, который реализуется объектом user.
1.2 Сложные сценарии
Интерфейсы и типизация сложных структур
Интерфейсы позволяют создавать сложные типы данных, включая вложенные объекты и массивы.
Пример:
"use strict";
let user = {
name: 'Alice',
age: 30,
address: {
street: '123 Main St',
city: 'Wonderland',
zipCode: '12345'
}
};
console.log(user.address.city); // Вывод: Wonderland
interface Address {
street: string;
city: string;
zipCode: string;
}
interface User {
name: string;
age: number;
address: Address;
}
let user: User = {
name: 'Alice',
age: 30,
address: {
street: '123 Main St',
city: 'Wonderland',
zipCode: '12345'
}
};
console.log(user.address.city); // Вывод: Wonderland
В этом примере интерфейс User содержит вложенный объект address, который соответствует интерфейсу Address.
Индексируемые типы
Интерфейсы могут определять индексируемые типы, которые позволяют доступ к значениям через ключи динамически определенного типа.
Пример:
"use strict";
let colors = ['red', 'green', 'blue'];
console.log(colors[0]); // Вывод: red
console.log(colors[1]); // Вывод: green
console.log(colors[2]); // Вывод: blue
interface StringArray {
[index: number]: string;
}
let colors: StringArray = ['red', 'green', 'blue'];
console.log(colors[0]); // Вывод: red
console.log(colors[1]); // Вывод: green
console.log(colors[2]); // Вывод: blue
В этом примере интерфейс StringArray описывает массив строк, где каждый элемент имеет строковый тип и доступен по числовому индексу.
Интерфейсы для функций
Интерфейсы могут использоваться для описания типов функций, включая параметры и возвращаемые значения.
Пример:
"use strict";
let mySearch;
mySearch = function (source, subString) {
return source.indexOf(subString) > -1;
};
console.log(mySearch('Hello, world', 'world')); // Вывод: true
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string): boolean {
return source.indexOf(subString) > -1;
};
console.log(mySearch('Hello, world', 'world')); // Вывод: true
В этом примере интерфейс SearchFunc описывает функцию, которая принимает два параметра типа string и возвращает значение типа boolean.
1.3 Примеры
Примеры использования интерфейсов в реальных проектах
Интерфейсы широко используются в реальных проектах для обеспечения типовой безопасности, улучшения читаемости кода и упрощения поддержки.
Пример 1: Модели данных
Интерфейсы используются для описания моделей данных, которые обрабатываются в приложении:
"use strict";
let products = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Mouse', price: 25, description: 'Wireless mouse' }
];
function getProductDetails(product) {
return `Product: ${product.name}, Price: $${product.price}`;
}
console.log(getProductDetails(products[0])); // Вывод: Product: Laptop, Price: $999
interface Product {
id: number;
name: string;
price: number;
description?: string;
}
let products: Product[] = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Mouse', price: 25, description: 'Wireless mouse' }
];
function getProductDetails(product: Product): string {
return `Product: ${product.name}, Price: $${product.price}`;
}
console.log(getProductDetails(products[0])); // Вывод: Product: Laptop, Price: $999
В этом примере интерфейс Product описывает структуру объекта продукта, включая опциональное свойство description.
Пример 2: Конфигурация приложения
Интерфейсы могут использоваться для описания конфигурационных объектов, которые передаются в функции или классы:
"use strict";
function initializeApp(config) {
console.log(`Initializing app with API URL: ${config.apiUrl}`);
}
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retryAttempts: 3
};
initializeApp(config); // Вывод: Initializing app with API URL: https://api.example.com
interface AppConfig {
apiUrl: string;
timeout: number;
retryAttempts: number;
}
function initializeApp(config: AppConfig): void {
console.log(`Initializing app with API URL: ${config.apiUrl}`);
}
const config: AppConfig = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retryAttempts: 3
};
initializeApp(config); // Вывод: Initializing app with API URL: https://api.example.com
В этом примере интерфейс AppConfig описывает структуру конфигурационного объекта, который используется для инициализации приложения.
Пример 3: Взаимодействие с API
Интерфейсы часто используются для типизации данных, получаемых из внешних API:
"use strict";
async function fetchUser(userId) {
// Используем открытое API для получения данных о пользователе
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
if (!response.ok) {
throw new Error(`Ошибка HTTP: ${response.status}`);
}
const user = await response.json();
return user;
}
fetchUser(1).then(user => console.log(user));
// Пример вывода: { id: 1, name: 'Leanne Graham', email: 'Sincere@april.biz' } ...
interface User {
id: number;
name: string;
email: string;
}
async function fetchUser(userId: number): Promise<User> {
// Используем открытое API для получения данных о пользователе
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
if (!response.ok) {
throw new Error(`Ошибка HTTP: ${response.status}`);
}
const user: User = await response.json();
return user;
}
fetchUser(1).then(user => console.log(user));
// Пример вывода: { id: 1, name: 'Leanne Graham', email: 'Sincere@april.biz' }
В этом примере интерфейс User описывает структуру данных, возвращаемых API, что позволяет TypeScript проверять корректность типов при работе с ответом API.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ