Два специальных типа в TypeScript — any и unknown — часто вызывают путаницу, но разница между ними критична для безопасности.
any — это «выключатель» проверки типов. Он позволяет делать с переменной что угодно, что часто приводит к ошибкам в рантайме. Это плохая практика, если используется без веской причины.
unknown — это безопасный аналог any. Переменная этого типа может хранить любое значение, но TypeScript запретит вам использовать её методы или свойства, пока вы явно не проверите её тип (сужение типа).
В этом уроке мы разберем:
- Почему
unknownлучше, чемany. - Как перевести небезопасный код на
unknown. - Способы сужения типа
unknownдо строки, числа или объекта.
- Модуль 1: Введение в TypeScript
- Модуль 2: Примитивные типы
- Модуль 3: Специальные типы
- Тип any.
- Тип unknown.
- Тип void.
- Тип never.
- Разница между any и unknown.
- Модуль 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. Any vs Unknown
В левой колонке перечислены характеристики поведения типов в TypeScript, а в правой — указано, к какому типу (any, unknown или к обоим) относится каждая характеристика. Сопоставьте каждое описание поведения с соответствующим типом или категорией. Это поможет понять ключевые различия между any и unknown при работе с динамическими данными.
2. Повышение безопасности
В этом задании вам нужно повысить типобезопасность функции, обрабатывающей ответ от сервера. Замените тип `any` на более строгий тип, который заставляет выполнять проверки перед использованием значения. Это поможет избежать случайных ошибок типизации. Вставьте правильный тип в отмеченное место, чтобы код стал безопаснее, но остался рабочим.
function processServerResponse(data: input1S): string {
// Предполагаем, что data - это объект с полем message типа string
if (typeof data === 'object' && data !== null && 'message' in data) {
return data.message;
}
return 'Ошибка: неверный формат данных';
}3. Небезопасные места
В представленном фрагменте кода TypeScript используются переменные с типами `any` и `unknown`. Внимательно изучите код и отметьте все места, где вызывается метод или обращение к свойству, которое компилятор TypeScript разрешает исключительно из-за использования типа `any` (то есть где отсутствует реальная проверка типа, которая потребовалась бы для `unknown`). Не отмечайте строки с объявлениями переменных, проверками типов (например, `typeof`), вызовами методов у переменной `unknown` после сужения типа или другие части кода, не соответствующие условию.
let valueAny: any = 'Hello';
let valueUnknown: unknown = 123;
// Небезопасные операции для any
{{valueAny.toUpperCase()~|~t1}};
{{valueAny.someMethod()~|~t2}};
{{valueAny.property~|~t3}};
// Проверка типа для unknown
if (typeof valueUnknown === 'number') {
{{valueUnknown.toFixed(2)~|~d1}}; // Безопасный вызов после сужения типа
}
// Еще один небезопасный вызов для any
{{valueAny.anotherMethod()~|~t4}};
// Обращение к свойству у объекта с типом any
let obj: any = { x: 10 };
console.log({{obj.x~|~t5}});
// Вызов метода у строкового литерала (тип известен, не any)
{{'test'.toUpperCase()~|~d2}};4. Валидация JSON
Из предложенных строк соберите корректную функцию на TypeScript, которая принимает аргумент типа unknown, проверяет, является ли он строкой, и если да, то парсит её как JSON, возвращая результат. Если аргумент не строка, функция должна возвращать null. В решении не должно быть лишних строк, не влияющих на логику валидации. Задание направлено на понимание разницы между типами any и unknown и их использование в контексте проверки типов.
function parseJson(input: unknown): any { if (typeof input === 'string') { const parsed = JSON.parse(input); return parsed; } return null;} let x: any = input; if (typeof input === 'number') { console.log(input);5. Компиляция кода
Проанализируйте два фрагмента кода на TypeScript. Один использует тип `any`, другой — `unknown`. Оба пытаются получить доступ к свойству `name` у переменной. Определите, какой из примеров вызовет ошибку компиляции (ошибку проверки типов) в TypeScript.
Пример 1 (с типом any):
let data: any = { name: "Alice" };
console.log(data.name); // Прямой доступ к свойствуПример 2 (с типом unknown):
let data: unknown = { name: "Bob" };
console.log(data.name); // Прямой доступ к свойству6. Алгоритм безопасного доступа
Проанализируйте TypeScript-код сверху и восстановите последовательность логических шагов выполнения программы. Шаги снизу перемешаны — расставьте их в правильном порядке, чтобы отразить, как программа безопасно обрабатывает данные типа unknown, проверяет их тип и выполняет соответствующую операцию.
function processValue(value: unknown): string {
if (typeof value === 'string') {
return `String: ${value.toUpperCase()}`;
} else if (typeof value === 'number') {
return `Number: ${value.toFixed(2)}`;
} else {
return 'Unsupported type';
}
}
const result = processValue('hello');
console.log(result);7. Типы данных
В объявлении функции на TypeScript разметьте аннотации типов для параметров и возвращаемого значения. Для каждого выделенного фрагмента укажите, является ли он типом `any`, `unknown` или `void`. Обратите внимание на расположение двоеточий и ключевых слов типов.
function process(data: {{any~|~t1}}, input: {{unknown~|~t2}}): {{void~|~t3}} {
// ...
}8. Type Assertion
Перед вами строки TypeScript-кода, демонстрирующие работу с типом unknown и приведением типов (type assertion). Переменная unknown требует проверки типа перед использованием. Строки перемешаны. Восстановите правильную последовательность кода, где сначала объявляется переменная типа unknown, затем выполняется проверка её типа с помощью typeof, и только после этого, с использованием утверждения типа (as), переменная приводится к конкретному типу для дальнейших операций. Обратите внимание, что прямое приведение типов (as) считается плохой практикой, но в данном примере используется для демонстрации.
let value: unknown = 'Hello, TypeScript!'; let length: number = (value as string).length;} console.log(length);if (typeof value === 'string') {