Переменные и константы в 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 const— 10.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) вместо as — 12.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-объекта и ждать immutability | const ≠ deep freeze | readonly / новый объект |
const arr = [] | never[] | const arr: Item[] = [] |
| Деструктуризация без типа параметра | слабые подсказки | : User на параметре |
! вместо проверки | ложная уверенность | if (x !== null) |
var в циклах | утечка в замыканиях | let |
Практика
- Опишите
Settingsсreadonlyи функциюupdateSettings(s, patch)через spread. - Напишите
createOrder({ productId, qty }: { productId: string; qty: number })с деструктуризацией. - Объявите
let token: string | null = nullи функциюrequireToken()с сужением. - Создайте
const routes = ["home", "profile"] as constи типRouteчерезtypeof. - Включите
noImplicitAnyи исправьте всеletбез выведенного типа.
Смежные статьи
- Типы — примитивы, union,
as const - Ветвления — narrowing после проверки
- Коллекции —
readonlyмассивы - Функции — параметры и rest
- Справочник — Справочник — основы типизации
- JS: 19