← Курс/Базовые типы TypeScript#141 из 257+25 XP

Базовые типы TypeScript

Примитивные типы

TypeScript напрямую отражает примитивы JavaScript, добавляя к ним аннотации:

const name: string = 'Алексей'
const age: number = 30          // целые и дробные — один тип number
const isActive: boolean = true
const nothing: null = null
const notSet: undefined = undefined

TypeScript умеет **выводить** типы автоматически (type inference) — явные аннотации не всегда нужны:

const name = 'Алексей'   // TypeScript сам выводит тип string
const age = 30            // TypeScript выводит тип number

void и never

**void** — функция ничего не возвращает (возвращает undefined):

function logMessage(msg: string): void {
  console.log(msg)
  // нет return, или return без значения
}

**never** — функция никогда не возвращает (бесконечный цикл или всегда бросает ошибку):

function throwError(message: string): never {
  throw new Error(message)
  // код после throw никогда не выполнится
}

function infiniteLoop(): never {
  while (true) { }
}

any — избегай его

**any** отключает проверку типов. Это как вернуться к обычному JavaScript — TS не будет проверять что вы делаете с переменной:

let value: any = 'строка'
value = 42           // OK — any разрешает что угодно
value.foo.bar.baz()  // OK для TS, но ошибка в runtime!

Используй any только как крайнее средство при миграции JS → TS.

unknown — безопасная замена any

**unknown** — тип «мы не знаем что это», но в отличие от any, перед использованием нужна **явная проверка**:

let value: unknown = fetchSomeData()

// Нельзя без проверки:
value.toUpperCase()  // Ошибка: Object is of type 'unknown'

// Нужна проверка типа:
if (typeof value === 'string') {
  value.toUpperCase()  // OK — TypeScript теперь знает что это string
}

Разница any vs unknown

| Характеристика | any | unknown |

|---|---|---|

| Присвоить что угодно | ✓ | ✓ |

| Использовать без проверки | ✓ | ✗ |

| Безопасность | нет | есть |

| Когда использовать | legacy код | API ответы, JSON |

// Типичный пример unknown — ответ от API:
async function fetchUser(id: number): Promise<unknown> {
  const response = await fetch(`/api/users/${id}`)
  return response.json()  // тип JSON неизвестен
}

const user = await fetchUser(1)  // тип: unknown

if (
  typeof user === 'object' &&
  user !== null &&
  'name' in user &&
  typeof (user as any).name === 'string'
) {
  console.log(user.name)  // теперь безопасно
}

Сводка типов

const a: string = 'текст'
const b: number = 42
const c: boolean = false
const d: null = null
const e: undefined = undefined
const f: any = 'что угодно'     // избегай
const g: unknown = getData()    // безопасная альтернатива any

function log(msg: string): void { console.log(msg) }
function fail(msg: string): never { throw new Error(msg) }

Примеры

Функция tsTypeOf определяет TypeScript-тип значения с правильной обработкой null, массивов и void

// TypeScript имеет более богатую систему типов чем typeof в JS.
// Эта функция определяет "TypeScript-тип" значения,
// правильно обрабатывая особые случаи.

function tsTypeOf(value) {
  // null — особый случай: typeof null === 'object' в JS (историческая ошибка)
  if (value === null) return 'null'

  // Массивы — в TS это Array<T>, а не просто object
  if (Array.isArray(value)) return 'array'

  // undefined — в TS обозначает void для возвращаемого значения
  if (typeof value === 'undefined') return 'undefined'

  // Все остальные случаи typeof корректны для TS
  // 'string', 'number', 'boolean', 'function', 'object', 'bigint', 'symbol'
  return typeof value
}

// Функция симулирует поведение unknown — требует проверку перед использованием
function useUnknown(value) {
  // unknown — нельзя использовать без проверки типа
  const type = tsTypeOf(value)

  if (type === 'string') {
    return `Строка: "${value.toUpperCase()}"`
  } else if (type === 'number') {
    return `Число: ${value.toFixed(2)}`
  } else if (type === 'boolean') {
    return `Булево: ${value ? 'true' : 'false'}`
  } else if (type === 'null') {
    return 'Значение: null'
  } else if (type === 'undefined') {
    return 'Значение: undefined'
  } else if (type === 'array') {
    return `Массив из ${value.length} элементов`
  } else if (type === 'object') {
    return `Объект с ключами: ${Object.keys(value).join(', ')}`
  } else if (type === 'function') {
    return `Функция: ${value.name || 'анонимная'}`
  }
  return `Неизвестный тип: ${type}`
}

// Демонстрация
const testValues = [
  'Привет',
  42,
  3.14,
  true,
  false,
  null,
  undefined,
  [1, 2, 3],
  { name: 'Алексей', age: 30 },
  function myFunc() {},
  () => {},
]

console.log('=== tsTypeOf ===')
testValues.forEach(v => {
  const display = v === null ? 'null' :
                  v === undefined ? 'undefined' :
                  Array.isArray(v) ? `[${v}]` :
                  typeof v === 'object' ? JSON.stringify(v) :
                  typeof v === 'function' ? `function ${v.name}` :
                  JSON.stringify(v)
  console.log(`tsTypeOf(${display}) => ${tsTypeOf(v)}`)
})

console.log('\n=== useUnknown (симуляция unknown) ===')
testValues.forEach(v => console.log(useUnknown(v)))