Перейти к основному содержимому

Переменные и константы в TypeScript

Разработчику

Дальше: Ветвления · Типы и типизация · Коллекции · Справочник — основы типизации


В runtime переменные в TypeScript — те же let и const, что в JavaScript. Отличие — контракт типа: компилятор знает, что можно присвоить, и подсказывает это в IDE.

Маршрут: Типы и типизацияпеременныеветвленияфункции.

База JS: переменные и область видимости. null / undefined в strict — 10.md §strictNullChecks.


const и let

ОбъявлениеПереназначение ссылкиКогда использовать
constнельзяпо умолчанию
letможносчётчики, переприсваивание
varустарелоне использовать
const appName = "IT Universe";
let counter = 0;
counter += 1;

// appName = "другое"; // ошибка

Разбор:

  • const не делает объект неизменяемым — запрещено только config = другойОбъект.
  • Поля объекта под const можно менять, если они не readonly.

Вывод типов (type inference)

TypeScript выводит тип из правой части, если аннотация не указана:

const total = 100; // number
const title = "Отчёт"; // string
const flags = [true, false]; // boolean[]

let score = 10;
score = 20; // OK
// score = "текст"; // ошибка

Разбор:

  • У const примитивов тип сужается до литерала только с as const10.md.
  • У let тип шире: number, не 10.

Обязательно ли писать let name: type?

Нет — в большинстве случаев TypeScript выводит тип сам. Явная запись let name: type нужна не «везде», а там, где компилятору не хватает контекста.

СитуацияАннотация при объявленииПри присвоенииПри использовании
const x = 10Не нужна (вывод number)Тип уже зафиксированПроверка по выведенному типу
let score = 10Не нужнаНовое значение должно быть numberТо же
let id; id = "a"Нужна (let id: string)Проверка совместимости с объявленным типом
Параметр функцииОбычно да (или контекст callback)Аргументы проверяются при вызове
Возврат функцииЧасто выводится; в API — явноreturn проверяется
Поле объекта в литералеЧасто выводится из значенияДоступ к полю по типу объекта

Аннотация при присвоении (x = value as string) — это уже утверждение (as), а не объявление типа; предпочитайте сужение через if — ниже и в 12.md.

Вся эта проверка выполняется на этапе TypeScript (tsc, IDE), не в runtime — 15.md.


Когда нужна явная аннотация

// Инициализация позже — тип обязателен
let userId: string;
userId = "u-42";

// Пустой массив без контекста → never[]
const items: string[] = [];

// Параметр функции (всегда типизируют или выводят из контекста)
function setPort(port: number): void {
console.log(port);
}

Разбор:

  • let x; без типа и без присваивания в strict даёт any (или ошибку при noImplicitAny) — избегайте.
  • Явная аннотация полезна на границах API: публичные функции, экспортируемые константы.

Аннотация против утверждения

КонструкцияПримерСмысл
Аннотацияconst x: string = "a"проверка совместимости
Утверждениеvalue as stringДоверие разработчика, проверка слабее
Утверждение !el!.focus()Разработчик обещает, что здесь не null — осторожно

Предпочитайте аннотации и сужение (if, typeof) вместо as12.md.


readonly на полях и переменных

type Point = {
readonly x: number;
readonly y: number;
};

const p: Point = { x: 10, y: 20 };
// p.x = 5; // ошибка

const ids: readonly number[] = [1, 2, 3];
// ids.push(4); // ошибка

Разбор:

  • readonlyповерхностная защита: вложенный объект внутри поля можно менять, если не помечен.
  • Для глубокой неизменяемости — Readonly<T> рекурсивно или иммутабельные обновления.

Обновление состояния, объявленного через const, — это новый объект:

type Settings = {
readonly theme: "light" | "dark";
readonly locale: string;
};

function withTheme(s: Settings, theme: Settings["theme"]): Settings {
return { ...s, theme };
}

Деструктуризация

Объекты

type User = {
id: string;
name: string;
email?: string;
};

function printUser({ id, name, email }: User): void {
console.log(id, name, email ?? "—");
}

const u: User = { id: "1", name: "Анна" };
const { name: displayName } = u;

Разбор:

  • Тип указывают у всего параметра { ... }: User, не у каждого поля отдельно.
  • Переименование: { name: displayName }.

Массивы и rest

const pair: [string, number] = ["score", 100];
const [label, value] = pair;

const [head, ...tail] = [1, 2, 3, 4];
// head: number, tail: number[]

Значения по умолчанию

function connect({
host = "localhost",
port = 3000,
}: {
host?: string;
port?: number;
}): void {
console.log(`${host}:${port}`);
}

Деструктуризация в const

const response = {
status: 200 as const,
data: { id: "1", name: "Ann" },
};

const {
data: { id, name },
} = response;

Разбор:

  • Вложенная деструктуризация сохраняет вывод типов для id и name.
  • При сложной форме лучше промежуточная переменная — читаемость.

strictNullChecks и переменные

С strict тип string не принимает null / undefined:

let title: string | null = null;

function render(t: string | null): string {
if (t === null) return "Без названия";
return t.toUpperCase();
}

Optional chaining при доступе к полям:

type Profile = { address?: { city?: string } };

function cityOf(p: Profile): string | undefined {
return p.address?.city;
}

Подробнее — 10.md; практика проекта — 6.md.


Переменные и модули

На верхнем уровне модуля const и let не попадают в глобальный объект (в ES-модулях), в отличие от старого var в скриптах.

// utils.ts
export const API_URL = "https://api.example.com";

// main.ts
import { API_URL } from "./utils.js";

Разбор:

  • Экспортируемые константы — частый способ задать контракт конфигурации с типом as const или явным union.

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

ОшибкаПричинаЧто делать
let x; без типанеявный anyинициализировать или : T
Менять поля const-объекта и ждать immutabilityconst ≠ deep freezereadonly / новый объект
const arr = []never[]const arr: Item[] = []
Деструктуризация без типа параметраслабые подсказки: User на параметре
! вместо проверкиложная уверенностьif (x !== null)
var в циклахутечка в замыканияхlet

Практика

  1. Опишите Settings с readonly и функцию updateSettings(s, patch) через spread.
  2. Напишите createOrder({ productId, qty }: { productId: string; qty: number }) с деструктуризацией.
  3. Объявите let token: string | null = null и функцию requireToken() с сужением.
  4. Создайте const routes = ["home", "profile"] as const и тип Route через typeof.
  5. Включите noImplicitAny и исправьте все let без выведенного типа.

Смежные статьи