3.1 Объекты в TypeScript
С объектами в JavaScript вы уже знакомы. Сейчас вы познакомитесь с объектами в TypeScript, а также с такой интересной вещью как интерфейсы. Мы подробно рассмотрим определение и типизацию объектов в TypeScript, а также использование интерфейсов для улучшения структуры и безопасности кода.
Определение объектов
Объекты в TypeScript, как и в JavaScript, представляют собой коллекции свойств, где каждое свойство имеет ключ и значение. Однако, в TypeScript мы можем явно указывать типы ключей и значений, что помогает избежать ошибок и улучшает читаемость кода.
1. Объявление и инициализация объектов
Пример:
let user: { name: string, age: number, isAdmin: boolean } = {
name: 'John Doe',
age: 30,
isAdmin: false
};
В этом примере мы объявляем объект user с тремя свойствами: name (строка), age (число) и isAdmin (логическое значение).
2. Доступ к свойствам объекта
Доступ к свойствам объекта осуществляется с помощью синтаксиса точечной нотации или квадратных скобок.
Пример:
console.log(user.name); // Вывод: John Doe
console.log(user['age']); // Вывод: 30
3. Изменение свойств объекта
Свойства объекта можно изменять после его инициализации.
Пример:
user.age = 31;
user['isAdmin'] = true;
console.log(user); // Вывод: { name: 'John Doe', age: 31, isAdmin: true }
3.2 Интерфейсы
Интерфейсы в TypeScript — это способ определения структуры объекта. Они позволяют задавать контракт/стандарт, который должен выполнять объект, и обеспечивают строгую проверку типов.
1. Определение интерфейсов
Интерфейсы определяются с помощью ключевого слова interface, за которым следует имя интерфейса и определение его свойств.
Пример:
interface User {
name: string;
age: number;
isAdmin: boolean;
}
let user: User = {
name: 'Alice',
age: 25,
isAdmin: true
};
В этом примере мы определяем интерфейс User, который описывает структуру объекта с тремя свойствами: name, age и isAdmin. Затем мы создаем объект user, который соответствует этому интерфейсу.
2. Опциональные свойства
Интерфейсы позволяют определять опциональные свойства с помощью символа ? после имени свойства. Опциональные свойства могут присутствовать в объекте, но их значение может отсутствовать.
Пример:
"use strict";
let user1 = {
name: 'Bob',
age: 40
};
let user2 = {
name: 'Charlie',
age: 35,
isAdmin: true
};
console.log(user1); // Вывод: { name: 'Bob', age: 40 }
console.log(user2); // Вывод: { name: 'Charlie', age: 35, isAdmin: true }
interface User {
name: string;
age: number;
isAdmin?: boolean; // Опциональное свойство
}
let user1: User = {
name: 'Bob',
age: 40
};
let user2: User = {
name: 'Charlie',
age: 35,
isAdmin: true
};
console.log(user1); // Вывод: { name: 'Bob', age: 40 }
console.log(user2); // Вывод: { name: 'Charlie', age: 35, isAdmin: true }
3. Интерфейсы для функций
Интерфейсы могут также использоваться для определения типов функций и методов.
Пример:
"use strict";
let calculator = {
add(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
}
};
console.log(calculator.add(5, 3)); // Вывод: 8
console.log(calculator.subtract(5, 3)); // Вывод: 2
interface MathOperations {
add(a: number, b: number): number;
subtract(a: number, b: number): number;
}
let calculator: MathOperations = {
add(a: number, b: number): number {
return a + b;
},
subtract(a: number, b: number): number {
return a - b;
}
};
console.log(calculator.add(5, 3)); // Вывод: 8
console.log(calculator.subtract(5, 3)); // Вывод: 2
В этом примере мы определяем интерфейс MathOperations, который описывает два метода: add() и subtract(). Затем мы создаем объект calculator, который реализует этот интерфейс.
4. Наследование интерфейсов
Интерфейсы могут наследоваться от других интерфейсов, что позволяет создавать новые интерфейсы на основе существующих.
Пример:
"use strict";
let employee = {
name: 'David',
age: 45,
employeeId: 12345,
position: 'Manager'
};
console.log(employee); // Вывод: { name: 'David', age: 45, employeeId: 12345, position: 'Manager' }
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: number;
position: string;
}
let employee: Employee = {
name: 'David',
age: 45,
employeeId: 12345,
position: 'Manager'
};
console.log(employee); // Вывод: { name: 'David', age: 45, employeeId: 12345, position: 'Manager' }
В этом примере интерфейс Employee наследует интерфейс Person, добавляя два новых свойства: employeeId и position. Объект employee реализует интерфейс Employee и, следовательно, также включает свойства интерфейса Person.
5. Индексируемые типы
Интерфейсы могут определять индексируемые типы, которые позволяют доступ к значениям через ключи определенного типа.
Пример:
"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 описывает массив строк, где каждый элемент имеет строковый тип и доступен по числовому индексу.
3.3 Примеры
Пример использования объектов и интерфейсов в реальном проекте
Для лучшего понимания, как использовать объекты и интерфейсы в TypeScript, рассмотрим пример простого приложения для управления задачами.
Пример приложения для управления задачами:
"use strict";
let tasks = [];
function addTask(task) {
tasks.push(task);
}
function completeTask(taskId) {
let task = tasks.find(t => t.id === taskId);
if (task) {
task.completed = true;
}
}
function getIncompleteTasks() {
return tasks.filter(task => !task.completed);
}
// Добавляем задачи
addTask({ id: 1, title: 'Learn TypeScript', completed: false });
addTask({ id: 2, title: 'Write an article', description: 'About TypeScript', completed: false });
// Завершаем задачу
completeTask(1);
// Получаем незавершенные задачи
let incompleteTasks = getIncompleteTasks();
console.log(incompleteTasks); // Вывод: [{ id: 2, title: 'Write an article', description: 'About TypeScript', completed: false }]
interface Task {
id: number;
title: string;
description?: string;
completed: boolean;
}
let tasks: Task[] = [];
function addTask(task: Task): void {
tasks.push(task);
}
function completeTask(taskId: number): void {
let task = tasks.find(t => t.id === taskId);
if (task) {
task.completed = true;
}
}
function getIncompleteTasks(): Task[] {
return tasks.filter(task => !task.completed);
}
// Добавляем задачи
addTask({ id: 1, title: 'Learn TypeScript', completed: false });
addTask({ id: 2, title: 'Write an article', description: 'About TypeScript', completed: false });
// Завершаем задачу
completeTask(1);
// Получаем незавершенные задачи
let incompleteTasks = getIncompleteTasks();
console.log(incompleteTasks); // Вывод: [{ id: 2, title: 'Write an article', description: 'About TypeScript', completed: false }]
В этом примере мы определяем интерфейс Task, который описывает структуру задачи. Затем мы создаем массив задач tasks и функции для добавления задач, завершения задач и получения незавершенных задач. Это демонстрирует, как использовать объекты и интерфейсы для структурирования данных и функций в приложении.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ