any — это «выход» из системы типов TypeScript. Переменная с типом any может быть чем угодно, и TypeScript перестаёт проверять операции с ней.
let value: any = 42
value = 'строка' // OK
value = true // OK
value = { name: 'test' } // OK
value.foo() // OK для TS, но может упасть в runtime
value[0].bar.baz // OK для TS — проверки отключеныИспользование any — плохая практика. Оно полностью убивает цель TypeScript. Оправданных случаев немного: миграция старого JS-кода, работа с очень динамичными данными, быстрое прототипирование.
unknown — это «безопасный any». Переменная типа unknown тоже может содержать любое значение, но TypeScript **запрещает** с ней что-либо делать без предварительной проверки типа.
let value: unknown = 'hello'
// Нельзя напрямую использовать:
value.toUpperCase() // Ошибка: Object is of type 'unknown'
value.length // Ошибка: Object is of type 'unknown'
// Нужно сначала сузить тип (narrowing):
if (typeof value === 'string') {
value.toUpperCase() // OK — TypeScript знает что value: string
}
if (typeof value === 'number') {
value.toFixed(2) // OK — TypeScript знает что value: number
}unknown идеален для данных из внешних источников: API-ответы, JSON.parse, данные из форм. Вы обязаны проверить тип перед использованием.
async function fetchData(): Promise<unknown> {
const response = await fetch('/api/data')
return response.json() // json() возвращает any, но мы помечаем как unknown
}
const data = await fetchData()
// Обязательная проверка перед использованием:
if (typeof data === 'object' && data !== null && 'name' in data) {
console.log((data as { name: string }).name)
}never — тип для значений, которые никогда не существуют. Он используется в трёх основных сценариях:
1. Функции, которые никогда не возвращают:
function throwError(message: string): never {
throw new Error(message)
// Код после throw никогда не выполнится
}
function infiniteLoop(): never {
while (true) { }
}2. Исчерпывающие проверки (exhaustive checks):
type Color = 'red' | 'green' | 'blue'
function getHex(color: Color): string {
switch (color) {
case 'red': return '#FF0000'
case 'green': return '#00FF00'
case 'blue': return '#0000FF'
default:
// Если добавить 'yellow' в Color но забыть обработать здесь —
// TypeScript выдаст ошибку: 'yellow' не assignable to never
const exhaustiveCheck: never = color
throw new Error(`Неизвестный цвет: ${exhaustiveCheck}`)
}
}3. Пустое объединение:
type Result = string & number // never — строка не может быть числом одновременно| Тип | Присвоение | Использование | Когда применять |
|-----|-----------|---------------|-----------------|
| any | Любое значение | Без ограничений | Миграция JS-кода |
| unknown | Любое значение | После проверки типа | Внешние данные, API |
| never | Только never | Недостижимый код | Исчерпывающие проверки |
Демонстрация концепций any, unknown и never через runtime-проверки в JavaScript
// === Концепция any: нет проверок ===
// В JS всё и так динамично, как any в TS
function processAny(value) {
// В TS: let value: any — полная свобода, но и полная опасность
try {
return value.toUpperCase()
} catch (e) {
return `Ошибка: ${e.message}`
}
}
console.log('=== any (без проверок) ===')
console.log(processAny('hello')) // 'HELLO'
console.log(processAny(42)) // 'Ошибка: value.toUpperCase is not a function'
// === Концепция unknown: обязательная проверка перед использованием ===
function processUnknown(value) {
// В TS: unknown требует сужения типа через typeof/instanceof
if (typeof value === 'string') {
return value.toUpperCase()
}
if (typeof value === 'number') {
return value.toFixed(2)
}
if (Array.isArray(value)) {
return `Массив из ${value.length} элементов`
}
return `Неизвестный тип: ${typeof value}`
}
console.log('\n=== unknown (безопасная обработка) ===')
console.log(processUnknown('hello')) // 'HELLO'
console.log(processUnknown(3.14159)) // '3.14'
console.log(processUnknown([1, 2, 3])) // 'Массив из 3 элементов'
console.log(processUnknown(true)) // 'Неизвестный тип: boolean'
// === Концепция never: исчерпывающие проверки ===
function getStatusMessage(status) {
switch (status) {
case 'loading': return 'Загрузка...'
case 'success': return 'Готово!'
case 'error': return 'Ошибка!'
default:
// В TS: const check: never = status — TS выдаст ошибку если добавить новый статус
throw new Error(`Необработанный статус: ${status}`)
}
}
console.log('\n=== never (исчерпывающая проверка) ===')
console.log(getStatusMessage('loading')) // 'Загрузка...'
console.log(getStatusMessage('success')) // 'Готово!'
console.log(getStatusMessage('error')) // 'Ошибка!'
try {
getStatusMessage('pending') // В TS это поймал бы компилятор через never
} catch (e) {
console.log(e.message) // 'Необработанный статус: pending'
}
// === Функция, которая никогда не возвращает (never) ===
function assertNever(message) {
// В TS: возвращаемый тип never
throw new Error(`Unreachable: ${message}`)
}
console.log('\n=== Функция никогда не возвращает ===')
try {
assertNever('этот код не должен выполняться')
} catch (e) {
console.log(e.message) // 'Unreachable: этот код не должен выполняться'
}any — это «выход» из системы типов TypeScript. Переменная с типом any может быть чем угодно, и TypeScript перестаёт проверять операции с ней.
let value: any = 42
value = 'строка' // OK
value = true // OK
value = { name: 'test' } // OK
value.foo() // OK для TS, но может упасть в runtime
value[0].bar.baz // OK для TS — проверки отключеныИспользование any — плохая практика. Оно полностью убивает цель TypeScript. Оправданных случаев немного: миграция старого JS-кода, работа с очень динамичными данными, быстрое прототипирование.
unknown — это «безопасный any». Переменная типа unknown тоже может содержать любое значение, но TypeScript **запрещает** с ней что-либо делать без предварительной проверки типа.
let value: unknown = 'hello'
// Нельзя напрямую использовать:
value.toUpperCase() // Ошибка: Object is of type 'unknown'
value.length // Ошибка: Object is of type 'unknown'
// Нужно сначала сузить тип (narrowing):
if (typeof value === 'string') {
value.toUpperCase() // OK — TypeScript знает что value: string
}
if (typeof value === 'number') {
value.toFixed(2) // OK — TypeScript знает что value: number
}unknown идеален для данных из внешних источников: API-ответы, JSON.parse, данные из форм. Вы обязаны проверить тип перед использованием.
async function fetchData(): Promise<unknown> {
const response = await fetch('/api/data')
return response.json() // json() возвращает any, но мы помечаем как unknown
}
const data = await fetchData()
// Обязательная проверка перед использованием:
if (typeof data === 'object' && data !== null && 'name' in data) {
console.log((data as { name: string }).name)
}never — тип для значений, которые никогда не существуют. Он используется в трёх основных сценариях:
1. Функции, которые никогда не возвращают:
function throwError(message: string): never {
throw new Error(message)
// Код после throw никогда не выполнится
}
function infiniteLoop(): never {
while (true) { }
}2. Исчерпывающие проверки (exhaustive checks):
type Color = 'red' | 'green' | 'blue'
function getHex(color: Color): string {
switch (color) {
case 'red': return '#FF0000'
case 'green': return '#00FF00'
case 'blue': return '#0000FF'
default:
// Если добавить 'yellow' в Color но забыть обработать здесь —
// TypeScript выдаст ошибку: 'yellow' не assignable to never
const exhaustiveCheck: never = color
throw new Error(`Неизвестный цвет: ${exhaustiveCheck}`)
}
}3. Пустое объединение:
type Result = string & number // never — строка не может быть числом одновременно| Тип | Присвоение | Использование | Когда применять |
|-----|-----------|---------------|-----------------|
| any | Любое значение | Без ограничений | Миграция JS-кода |
| unknown | Любое значение | После проверки типа | Внешние данные, API |
| never | Только never | Недостижимый код | Исчерпывающие проверки |
Демонстрация концепций any, unknown и never через runtime-проверки в JavaScript
// === Концепция any: нет проверок ===
// В JS всё и так динамично, как any в TS
function processAny(value) {
// В TS: let value: any — полная свобода, но и полная опасность
try {
return value.toUpperCase()
} catch (e) {
return `Ошибка: ${e.message}`
}
}
console.log('=== any (без проверок) ===')
console.log(processAny('hello')) // 'HELLO'
console.log(processAny(42)) // 'Ошибка: value.toUpperCase is not a function'
// === Концепция unknown: обязательная проверка перед использованием ===
function processUnknown(value) {
// В TS: unknown требует сужения типа через typeof/instanceof
if (typeof value === 'string') {
return value.toUpperCase()
}
if (typeof value === 'number') {
return value.toFixed(2)
}
if (Array.isArray(value)) {
return `Массив из ${value.length} элементов`
}
return `Неизвестный тип: ${typeof value}`
}
console.log('\n=== unknown (безопасная обработка) ===')
console.log(processUnknown('hello')) // 'HELLO'
console.log(processUnknown(3.14159)) // '3.14'
console.log(processUnknown([1, 2, 3])) // 'Массив из 3 элементов'
console.log(processUnknown(true)) // 'Неизвестный тип: boolean'
// === Концепция never: исчерпывающие проверки ===
function getStatusMessage(status) {
switch (status) {
case 'loading': return 'Загрузка...'
case 'success': return 'Готово!'
case 'error': return 'Ошибка!'
default:
// В TS: const check: never = status — TS выдаст ошибку если добавить новый статус
throw new Error(`Необработанный статус: ${status}`)
}
}
console.log('\n=== never (исчерпывающая проверка) ===')
console.log(getStatusMessage('loading')) // 'Загрузка...'
console.log(getStatusMessage('success')) // 'Готово!'
console.log(getStatusMessage('error')) // 'Ошибка!'
try {
getStatusMessage('pending') // В TS это поймал бы компилятор через never
} catch (e) {
console.log(e.message) // 'Необработанный статус: pending'
}
// === Функция, которая никогда не возвращает (never) ===
function assertNever(message) {
// В TS: возвращаемый тип never
throw new Error(`Unreachable: ${message}`)
}
console.log('\n=== Функция никогда не возвращает ===')
try {
assertNever('этот код не должен выполняться')
} catch (e) {
console.log(e.message) // 'Unreachable: этот код не должен выполняться'
}Реализуй функцию `safeProcess(value)`, которая безопасно обрабатывает значение неизвестного типа (как unknown в TypeScript): если строка — вернуть в верхнем регистре; если число — вернуть квадрат числа; если массив — вернуть его длину; иначе — бросить ошибку с сообщением "Неподдерживаемый тип: <тип>".
Используй Array.isArray(value) для проверки массива ПЕРЕД проверкой typeof object. Порядок проверок: сначала Array.isArray, потом typeof === "string", потом typeof === "number", в конце — throw new Error.
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке