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

Базовые типы данных TypeScript: string, number, boolean, null, undefined, void, never, symbol, bigint.

Зачем нужно

  • Примитивные типы — фундамент системы типов TypeScript
  • Они описывают самые базовые значения и позволяют компилятору ловить простейшие ошибки
  • Понимание различий между null, undefined, void и never критично для написания корректного кода

Где используется

  • Аннотации переменных, параметров функций и возвращаемых значений
  • Составные типы (union, intersection) строятся из примитивных
  • Generics и utility types оперируют примитивными типами

Предпосылки

  • Что такое TypeScript — что такое TS и как работает
  • Знание примитивных типов JavaScript

string

Строковые значения — одинарные, двойные кавычки или template literals:

let name: string = "Alice";
let greeting: string = 'Hello';
let message: string = `Welcome, ${name}!`;

// Ошибка:
let broken: string = 42;
// Error: Type 'number' is not assignable to type 'string'

number

Все числа — целые и дробные, включая Infinity, NaN, hex, octal, binary:

let age: number = 30;
let price: number = 19.99;
let hex: number = 0xff;
let binary: number = 0b1010;
let octal: number = 0o744;
let negative: number = -42;
let inf: number = Infinity;
let notANumber: number = NaN; // Технически number

// Ошибка:
let broken: number = "42";
// Error: Type 'string' is not assignable to type 'number'

boolean

Только true или false:

let isActive: boolean = true;
let isAdmin: boolean = false;

// Ошибка:
let broken: boolean = 0;
// Error: Type 'number' is not assignable to type 'boolean'

// Truthy/falsy — это JS-концепция, TS различает boolean и другие типы
if (isActive) {
  // ...
}

null и undefined

Два отдельных типа, каждый с единственным значением:

let nothing: null = null;
let notDefined: undefined = undefined;

// С strictNullChecks: true (рекомендуется!)
let name: string = null;      // Ошибка!
let age: number = undefined;  // Ошибка!

// Нужно явно указать что значение может быть null/undefined
let name: string | null = null;           // OK
let age: number | undefined = undefined;  // OK

// Без strictNullChecks — null и undefined присваиваются любому типу (опасно!)

Опциональные свойства и параметры

// Опциональное свойство — автоматически добавляет | undefined
interface User {
  name: string;
  age?: number; // number | undefined
}

// Опциональный параметр
function greet(name: string, title?: string): string {
  // title: string | undefined
  return title ? `${title} ${name}` : name;
}

void

Отсутствие возвращаемого значения у функции:

// Функция ничего не возвращает
function log(message: string): void {
  console.log(message);
}

// void допускает return без значения
function doSomething: void {
  if (Math.random > 0.5) {
    return; // OK
  }
  // неявный return — OK
}

// void переменная может быть только undefined
let v: void = undefined;
let v2: void = null; // Ошибка с strictNullChecks

void в callback-ах

// Важный нюанс: void в callback означает "возвращаемое значение игнорируется"
type Callback = (item: string) => void;

const items: string = ["a", "b", "c"];

// Array.push возвращает number, но это OK
// потому что forEach ожидает callback с void
items.forEach((item) => items.push(item.toUpperCase()));

never

Тип значения, которое никогда не возникнет:

// Функция, которая НИКОГДА не завершается
function throwError(message: string): never {
  throw new Error(message);
}

// Бесконечный цикл
function infiniteLoop: never {
  while (true) {
    // ...
  }
}

// never в exhaustive checks
type Shape = "circle" | "square" | "triangle";

function getArea(shape: Shape): number {
  switch (shape) {
    case "circle":
      return Math.PI;
    case "square":
      return 1;
    case "triangle":
      return 0.5;
    default:
      // Если добавить новый shape и забыть case — ошибка компиляции
      const _exhaustive: never = shape;
      throw new Error(`Unknown shape: ${shape}`);
  }
}

symbol

Уникальный и неизменяемый идентификатор:

let sym1: symbol = Symbol;
let sym2: symbol = Symbol("description");

// Каждый symbol уникален
console.log(sym1 === sym2); // false

// unique symbol — для констант
const MY_KEY: unique symbol = Symbol("MY_KEY");

// Используется как ключ объекта
const obj = {
  [MY_KEY]: "secret value",
};

// Well-known symbols
class MyIterable {
  *[Symbol.iterator] {
    yield 1;
    yield 2;
    yield 3;
  }
}

bigint

Целые числа произвольной точности (ES2020+):

let big: bigint = 100n;
let huge: bigint = BigInt(9007199254740991);

// Арифметика только между bigint
let sum: bigint = 100n + 200n; // OK
let mixed = 100n + 200;        // Ошибка! Нельзя смешивать bigint и number

// Сравнение с number допустимо
console.log(100n === 100);  // Ошибка (строгое равенство разных типов)
console.log(100n == 100);   // OK: true (нестрогое)
console.log(100n > 50);     // OK: true

Сводная таблица

Тип Значения Пример
string Текст "hello", 'world', `${x}`
number Числа (64-bit float) 42, 3.14, NaN, Infinity
boolean true / false true, false
null Намеренное отсутствие null
undefined Значение не задано undefined
void Нет возвращаемого значения function f: void {}
never Никогда не возникает throw, бесконечный цикл
symbol Уникальный идентификатор Symbol("key")
bigint Большие целые числа 100n, BigInt(999)

Вывод типов для примитивов

// TypeScript выводит типы автоматически
let x = "hello";       // string
let y = 42;             // number
let z = true;           // boolean

// const сужает тип до литерала
const a = "hello";     // "hello" (литеральный тип, не string)
const b = 42;           // 42 (не number)
const c = true;         // true (не boolean)

Частые ошибки

  1. Путать String и string — используйте string (маленькая буква). String — это wrapper object
// ПРАВИЛЬНО — примитивный тип
let name: string = "Alice";

// НЕПРАВИЛЬНО — object wrapper
let name: String = "Alice"; // Работает, но не рекомендуется
  1. Забывать про strictNullChecks — без него null и undefined совместимы со всем
  2. Путать void и undefinedvoid используется для функций, undefined — для значений
  3. Не использовать never для exhaustive checks — пропуск case в switch не обнаружится
  4. Использовать number для bigint — это разные типы, нельзя смешивать

Практика

  1. Объявите переменные каждого примитивного типа с явными аннотациями
  2. Попробуйте присвоить null переменной типа string — включите strictNullChecks
  3. Напишите функцию, которая возвращает never (выбрасывает ошибку)
  4. Создайте exhaustive switch с never — добавьте новый вариант и увидьте ошибку
  5. Поэкспериментируйте с const vs let и обратите внимание на вывод типов

Связанные темы

Ресурсы