В TypeScript иммутабельность данных играет важную роль в создании предсказуемого кода. Ключевое слово readonly позволяет объявлять свойства объектов, которые можно записать только один раз — при инициализации.
Это отличный инструмент для защиты id, конфигурационных настроек или ссылок, которые не должны изменяться в процессе работы приложения. Важно понимать, что readonly обеспечивает поверхностную неизменяемость: если свойство является объектом, его внутренние поля всё ещё могут быть изменены, если они сами не помемечены как только для чтения.
В этом уроке мы разберем:
- Синтаксис добавления модификатора в интерфейсы и типы.
- Разницу между
const(для переменных) иreadonly(для свойств). - Поведение компилятора при попытке перезаписи защищенных полей.
Эти знания помогут вам писать более безопасный код, предотвращая случайные мутации данных.
- Модуль 1: Введение в TypeScript
- Модуль 2: Примитивные типы
- Модуль 3: Специальные типы
- Модуль 4: Массивы
- Модуль 5: Кортежи (Tuples)
- Модуль 6: Объекты
- Модуль 7: Функции
- Модуль 8: Union типы
- Модуль 9: Литеральные типы
- Модуль 10: Type Aliases
- Модуль 11: Интерфейсы
- Модуль 12: Type Guards и Narrowing
- Модуль 13: Enums
- Модуль 14: Классы
- Модуль 15: Generics — основы
- Модуль 16: Generics — ограничения
- Модуль 17: Utility Types — базовые
- Модуль 18: Utility Types — работа с Union
- Модуль 19: Utility Types — функции
- Модуль 20: Type Assertions
- Модуль 21: Keyof и Typeof операторы
- Модуль 22: Mapped Types
- Модуль 23: Conditional Types
- Модуль 24: Discriminated Unions
- Модуль 25: Модули и типы
- Модуль 26: Declaration Files
- Модуль 27: Типизация асинхронного кода
- Модуль 28: Практические паттерны
1. Объявление интерфейса
В этом задании вам предстоит дополнить объявление интерфейса User, сделав поле id защищённым от изменений. Для этого в коде с пропуском нужно выбрать подходящее ключевое слово из выпадающего списка, чтобы получить корректный TypeScript-код, соответствующий теме readonly свойств. Обратите внимание на синтаксис объявления интерфейсов и модификаторы доступа к полям.
interface User {
input1S id: number;
name: string;
email: string;
}2. Попытка изменения
В этом фрагменте TypeScript-кода создаётся объект с использованием readonly-свойств. Затем происходит попытка изменить значение одного из этих свойств, что приводит к ошибке компиляции. Найдите строку, содержащую некорректное присваивание, и исправьте её, чтобы код стал рабочим.
interface User { readonly id: number; name: string;} const currentUser: User = { id: 1, name: 'Alice' };currentUser.id = 2;currentUser.name = 'Bob';3. Readonly в Type Alias
В TypeScript для защиты свойств объекта от изменений используется модификатор readonly. В этом задании объявлен псевдоним типа (type) для конфигурации приложения. Ваша задача — добавить модификатор readonly перед свойством apiKey, чтобы сделать его доступным только для чтения. Это предотвратит случайное изменение критически важного ключа API в коде. Вставьте нужное ключевое слово в отмеченное место, чтобы тип AppConfig корректно описывал неизменяемое свойство apiKey и изменяемое endpoint.
type AppConfig = {
input1S apiKey: string;
endpoint: string;
};
const config: AppConfig = {
apiKey: '12345-abcde',
endpoint: 'https://api.example.com'
};
// config.apiKey = 'new-key'; // Эта строка вызовет ошибку компиляции, если apiKey readonly4. Выбор защищенных полей
Внимательно изучите представленный интерфейс TypeScript. Ваша задача — отметить все свойства, которые защищены от изменения (объявлены как readonly). Не отмечайте изменяемые свойства, ключевые слова языка (например, interface, string, Date) или технические символы. Выделите только имена полей, которые нельзя перезаписать после инициализации объекта.
interface UserProfile {
{{readonly~|~t0}} {{id~|~t1}}: {{number~|~t2}};
{{username~|~t3}}: {{string~|~t4}};
{{email~|~t5}}: {{string~|~t6}};
{{readonly~|~t7}} {{createdAt~|~t8}}: {{Date~|~t9}};
{{age~|~t10}}?: {{number~|~t11}};
}5. Поверхностная неизменяемость
Проанализируйте приведённый код TypeScript, в котором объект имеет свойство, помеченное как readonly, но это свойство является массивом. Обратите внимание на операцию push внутри массива. Выберите все верные утверждения о поведении этого кода: будет ли он успешно скомпилирован и изменится ли содержимое массива после выполнения.
interface Config {
readonly data: number[];
}
const config: Config = {
data: [10, 20, 30]
};
// Попытка изменить массив
config.data.push(40);
console.log(config.data);6. Сборка безопасного интерфейса
Из предложенных строк соберите интерфейс Transaction с полями: id (число), amount (только для чтения, число), sender (только для чтения, строка) и receiver (строка). Поля должны быть объявлены именно в таком порядке. Лишние строки не используйте.
interface Transaction { id: number; readonly amount: number; readonly sender: string; receiver: string;} amount: number; sender: string; receiver: readonly string;7. Анализ жизненного цикла объекта
Проанализируйте TypeScript-код сверху и восстановите последовательность шагов, описывающих жизненный цикл объекта с readonly свойством. Шаги снизу перемешаны — расставьте их в правильном порядке, чтобы отразить, как программа объявляет тип, создаёт объект, читает свойства и пытается изменить readonly свойство.
interface User {
readonly id: number;
name: string;
}
const user: User = { id: 1, name: "Alice" };
console.log(user.id);
console.log(user.name);
// user.id = 2; // Ошибка компиляции: Cannot assign to 'id' because it is a read-only property.8. Разметка синтаксиса
Разметьте синтаксис объявления свойства в интерфейсе TypeScript. Укажите для каждого выделенного фрагмента, является ли он модификатором readonly, именем свойства или типом данных. Это поможет закрепить понимание структуры объявления свойств в объектных типах.
interface User {
{{readonly~|~t1}} {{id~|~t2}}: {{number~|~t3}};
}