Типы данных и типизация в TypeScript
Дальше: Переменные · Функции · Дженерики · Справочник — основы и объединения
TypeScript добавляет к JavaScript статическую проверку типов: ошибки несовместимости данных ловятся до запуска, IDE подсказывает поля и методы по контракту. Удобный порядок чтения — первая программа, эта статья, переменные, функции, классы.
Сначала: типы в JavaScript — динамическая модель, с которой сравнивают TS. Общие определения — типы данных и типизация в базовом разделе.
Блоки справочника 301 в этой статье
| Блок Справочник по TypeScript | Где в этой статье |
|---|---|
| §1 Основы типизации | примитивы, unknown, вывод, сужение типов (narrowing) |
| §3 Объединения и пересечения | union/intersection |
| §7 Утилитарные типы | Utility types |
| §2 Составные типы | массивы, кортежи здесь; Map/Record — Коллекции и массивы в TypeScript |
Полная карта 18 блоков — индекс раздела.
JavaScript и TypeScript
Play ITЗагрузка интерактивного демо…
Play ITЗагрузка интерактивного демо…
Play ITЗагрузка интерактивного демо…
— одна среда, два уровня
JavaScript — динамически типизирован: тип привязан к значению в runtime. TypeScript — статическая надстройка: компилятор анализирует код и выдаёт JavaScript; типы в .js не попадают.
| JavaScript | TypeScript | |
|---|---|---|
| Когда проверяются типы | При выполнении | При компиляции (tsc, IDE) |
Ошибка строка + объект | Может всплыть в runtime | Часто видна в редакторе сразу |
| Справочник по синтаксису типов | — | Справочник по TypeScript |
TypeScript включает типы значений JS (number, string, object, …) и добавляет свои — unknown, union (объединение типов через |), utility-типы, дженерики. Развёрнутое сравнение JS и TS с примерами и критериями выбора — Сравнение JavaScript и TypeScript. Обзор в контексте курса JS — Обзор TypeScript в JS; оглавление раздела — О разделе.
TypeScript и типичные проблемы JavaScript
В JavaScript тип привязан к значению в момент выполнения. В больших кодовых базах это даёт типичные боли:
| Проблема JS | Как помогает TS |
|---|---|
Опечатка в имени поля (user.nmae) | Ошибка в IDE и при tsc |
| Несовместимые аргументы функции | Проверка сигнатуры на всех вызовах |
| Рефакторинг API (переименование поля) | Поиск всех мест по проекту |
"Тихий" undefined / null | strictNullChecks, union, сужение типов |
| Внешний JSON без схемы | unknown + guard или Zod — Рекомендации по разработке на TypeScript |
TypeScript дополняет тесты и валидацию сети: данные с сервера по-прежнему нужно парсить, зато класс ошибок внутри кода ловится до запуска. Исторический контекст — История TypeScript.
Статическая типизация
Статическая типизация означает: компилятор (и tsserver в IDE) строит модель типов по исходникам и сообщает о несовместимости до node или открытия страницы в браузере.
| Динамика (JS) | Статика (TS) | |
|---|---|---|
| Когда видна ошибка | Часто в runtime | На этапе разработки / CI |
| Где живут типы | У значения | В анализе кода; в .js не попадают |
| Изменение контракта | Может "пройти" до теста | Подсветка всех вызовов |
Проверку выполняют инструменты TypeScript (tsc, языковой сервер), движок JavaScript типы не анализирует — см. "Где выполняется проверка типов" и Компиляция.
Типобезопасность (type safety)
Типобезопасность — свойство кода: операции применяются только к значениям, совместимым с контрактом типа. В строгом TS это означает:
- меньше неявных приведений и "магии"
any; - явные ветки для
null/undefined; - сужение типа (narrowing) перед доступом к полям
unknown;
Полная безопасность в production достигается слоями — TS + тесты + runtime-валидация границ (HTTP, формы, localStorage). TS закрывает ошибки логики типов в коде; Zod/Valibot — несоответствие внешних данных.
Структурная типизация
TypeScript использует структурную (structural) типизацию: совместимость определяется набором полей и методов, без учёта имени типа (в отличие от номинальной модели Java/C#).
type Point = { x: number; y: number };
function draw(p: Point) {
console.log(p.x, p.y);
}
// Отдельный type alias — но форма та же
draw({ x: 1, y: 2 }); // OK
Функция ожидает объект с полями x и y типа number. Подойдёт любой объект с такой формой, даже без отдельного alias Point. Это близко к утиной типизации в JS, только проверка идёт до запуска.
Утиная типизация в JS и структурная в TS
| JavaScript (утиная) | TypeScript (структурная) | |
|---|---|---|
| Критерий совместимости | "Если ходит как утка…" — есть нужные поля/методы | Та же идея формы, но проверяется компилятором |
| Когда ломается | В runtime при вызове | На этапе tsc / в IDE |
| Имена типов | Не важны | Имена interface / type — для людей; совместимость по полям |
В номинальных языках (Java, C#) тип A и тип B с одинаковыми полями — разные, если не объявлено наследование. В TS два alias с одной формой взаимозаменяемы — отсюда важность branded types, когда нужна "номинальность" — Паттерны.
Если двум типам с одинаковой формой нужны разные имена в проверке, используют branded types или классы — см. Паттерны и Справочник — распространённые паттерны.
Проектирование типов и принцип надёжности
Хорошие типы в TS — это контракты, которые сложно нарушить случайно:
- Узкие union вместо
stringдля кодов состояния ("idle" | "loading" | "error"). - Discriminated union с полем
kind/type— исчерпывающийswitchиnever— Операторы и условные ветвления в TypeScript, Паттерны в TypeScript. - Разделение слоёв: DTO (Data Transfer Object — форма данных с API) отдельно от domain-модели (бизнес-логика) — Рекомендации по разработке на TypeScript, TypeScript и Node.js.
Закон подстановки Лискова (LSP)
В ООП LSP: подтип должен без сюрпризов подставляться вместо базового типа. В TypeScript с структурной моделью это проявляется так:
- объект с дополнительными полями часто совместим с более узким ожиданием (excess property check действует на литералы, не на все случаи);
- функция с более узким параметром или более широким возвратом может быть несовместима с ожидаемой сигнатурой (контравариантность параметров).
type Animal = { name: string };
type Dog = Animal & { breed: string };
function greet(a: Animal): void {
console.log(a.name);
}
const d: Dog = { name: "Рекс", breed: "овчарка" };
greet(d); // OK: Dog структурно подходит под Animal
Проектируя иерархии, предпочитайте композицию и явные union вместо глубокого наследования — классы, Паттерны. "Надёжность" типов в команде закрепляется strict, code review и запретом нового any без причины.
Типы и значения
| Уровень | Что это | Пример |
|---|---|---|
| Тип | Контракт, проверяется компилятором | interface User { id: string; name: string } |
| Значение | Данные в runtime (обычный JS) | const u: User = { id: "1", name: "Анна" } |
Удобный порядок работы: сначала описать контракт (type / interface), затем реализацию. Ошибки в контракте IDE покажет до node или сборки bundler.
type Role = "admin" | "user";
interface Account {
id: string;
role: Role;
}
function canDelete(account: Account): boolean {
return account.role === "admin";
}
const me: Account = { id: "u-42", role: "user" };
console.log(canDelete(me)); // false
Примитивные типы
TypeScript наследует примитивы ECMAScript:
| Тип | Назначение |
|---|---|
string | Текст |
number | Все числа JS, включая NaN, Infinity |
boolean | true / false |
bigint | Целые произвольной длины |
symbol | Уникальные идентификаторы |
null | Явное отсутствие значения |
undefined | Не инициализировано / отсутствует |
let title: string = "Отчёт";
let count: number = 10_000;
let ok: boolean = true;
Запись 10_000 — numeric separator для читаемости; значение то же, что 10000. Аннотация : string не даст присвоить число без явного преобразования.
Специальные типы TypeScript
| Тип | Смысл | Когда использовать |
|---|---|---|
void | Функция ничего полезного не возвращает | function log(msg: string): void |
never | Значение не возникает (throw, бесконечный цикл) | exhaustive switch, guard |
any | Проверка типов отключена | Legacy, крайний случай |
unknown | Любое значение, но нельзя трогать без проверки | JSON, catch, внешний ввод |
any и unknown — когда что использовать
any — "выключатель" проверки: значение можно присвоить куда угодно, вызвать любой метод, передать в любую функцию. Компилятор пропускает ошибки — поведение как в нетипизированном JavaScript.
unknown — "безопасный контейнер": в переменную можно положить что угодно, но использовать её можно только после сужения типа (narrowing) — проверки через typeof, in, type predicate или утверждения с реальной проверкой.
let a: any = fetchSomething();
a.foo.bar(); // компилятор молчит — ошибка возможна в runtime
let u: unknown = fetchSomething();
// u.foo; // ошибка: Object is of type 'unknown'
if (typeof u === "object" && u !== null && "id" in u) {
const o = u as { id: string };
console.log(o.id);
}
| Критерий | any | unknown |
|---|---|---|
Присвоение в string, number, … | без проверки | только после narrowing |
| Вызов методов | разрешён | запрещён до сужения |
| Передача в типизированную функцию | разрешена | только после сужения |
| Типичный источник | legacy, @types с дырами | JSON.parse, catch, response.json() |
Правило: для внешних данных начинайте с unknown, не с any. Подробнее про валидацию и командные правила — Рекомендации.
Код ITЗагрузка примера кода…
Тип never показывает компилятору, что после throw выполнение не продолжается. unknown заставляет сузить тип перед доступом к полям — это безопаснее, чем any.
anyКаждый новый any отключает защиту TS. Для API и форм — unknown + проверка или библиотека валидации (Zod, Valibot). Правила проекта — рекомендации.
null, undefined и strictNullChecks
В JavaScript null и undefined часто смешивают. С флагом strictNullChecks (входит в strict) тип string не включает null/undefined — их нужно явно добавить в union:
type Name = string | null;
function greet(name: Name): string {
if (name === null) {
return "Гость";
}
return `Привет, ${name}`;
}
Типичная ошибка компилятора: Object is possibly 'undefined'. Решения:
- проверка
if (x !== undefined); - оператор
??(значение по умолчанию); - optional chaining
user?.profile?.email; - не злоупотреблять non-null assertion
!без реальной проверки.
Объекты — type, interface, опциональность
interface — удобен для объектов и расширения (extends).
type — union, tuple, mapped types, вычисляемые типы.
Сравнение interface и type — Синтаксис §interface и type.
Обязательные и опциональные поля
Обязательное поле — должно присутствовать при создании объекта (если не задано значение по умолчанию в деструктуризации параметра). Опциональное — может отсутствовать; тип поля тогда включает undefined.
| Запись | Смысл | Тип поля |
|---|---|---|
id: string | обязательно | string |
email?: string | можно не передавать | string | undefined |
readonly createdAt: string | обязательно, нельзя переприсвоить | string |
interface User {
id: string; // обязательное
email: string; // обязательное
nickname?: string; // опциональное
readonly createdAt: string;
}
// OK
const u1: User = { id: "1", email: "a@b.c", createdAt: "2024-01-01" };
// OK — nickname опущен
const u2: User = { id: "2", email: "x@y.z", createdAt: "2024-02-01" };
// Ошибка — нет обязательного email
// const bad: User = { id: "3", createdAt: "..." };
Utility Required<T> делает все поля обязательными; Partial<T> — все опциональными (удобно для PATCH и форм):
type UserPatch = Partial<Pick<User, "email" | "nickname">>;
type UserRow = Required<User>; // nickname тоже обязателен
type PublicUser = Pick<User, "id" | "nickname">;
Разбор:
?— свойство может отсутствовать (undefined).readonly— нельзя переприсвоить поле после создания объекта.Pick— utility-тип: подмножество полей (см. ниже).
Вложенные объекты можно описать inline или вынести в отдельный тип:
interface ServerConfig {
host: string;
port: number;
}
interface AppConfig {
server: ServerConfig;
debug: boolean;
}
Подробнее про interface и type — Синтаксис TypeScript. Таблицы полей — Справочник — интерфейсы.
Массивы и кортежи
Полный разбор
Map,Set,Recordи выбор структуры — коллекции (Справочник — составные типы).
const ids: number[] = [1, 2, 3];
const tags: Array<string> = ["ts", "js"];
// Кортеж: фиксированная длина и типы по позициям
type Rgb = [number, number, number];
const red: Rgb = [255, 0, 0];
type HttpResult = [status: number, body: string];
Разбор:
number[]иArray<number>эквивалентны.- Кортеж
[number, number, number]не примет[255, 0]— не хватает элемента. - Именованные элементы кортежа (
status:) улучшают подсказки IDE.
Коллекции Map, Set, Record — коллекции и массивы, Справочник — составные типы.
Union и intersection
Union (|) — объединение типов: значение соответствует одному из перечисленных вариантов.
type Id = string | number;
type Status = "idle" | "loading" | "success" | "error";
function formatId(id: Id): string {
if (typeof id === "string") {
return id.toUpperCase();
}
return id.toFixed(0);
}
Intersection (&) — объединение требований:
type Named = { name: string };
type Timestamped = { createdAt: string };
type Entity = Named & Timestamped;
// { name: string; createdAt: string }
Literal union ("admin" | "user") — основа discriminated union для состояний UI и команд API — операторы и ветвления, Паттерны.
Литеральные типы и enum
Строковые/числовые литералы сужают допустимые значения:
type Theme = "light" | "dark";
const theme: Theme = "light";
// theme = "blue"; // ошибка компиляции
enum — именованный набор констант (в JS генерирует объект):
enum Direction {
Up,
Down,
Left,
Right,
}
enum PaymentStatus {
Pending = "PENDING",
Paid = "PAID",
Failed = "FAILED",
}
В новых проектах часто предпочитают as const + union вместо enum (меньше сюрпризов при сборке). Оба подхода описаны в справочнике.
Вывод типов (type inference)
Вывод типов (type inference) — компилятор сам определяет тип из контекста: правой части присваивания, return, аргументов при вызове generic-функции. Явная аннотация не всегда нужна:
// Тип name выведен как string
const name = "Алиса";
// Тип параметров и возврата выводится из тела
function double(n: number) {
return n * 2;
}
Подробная таблица "когда писать : T" — Переменные — обязательно ли писать аннотацию.
Явно указывайте типы там, где:
- публичный API модуля (экспортируемые функции);
- компилятор выводит слишком широкий тип (
stringвместо"ok" | "fail"); - пустой массив
[]без контекста становитсяnever[].
// Плохо без контекста
const items = []; // never[]
// Лучше
const items: string[] = [];
Слишком широкий тип
Широкий тип — когда выведенный тип допускает больше значений, чем нужно по смыслу. Компилятор не ошибается, но теряется точность контракта.
const status = "ok"; // выведено: string, а не "ok"
// status = "fail"; // компилятор разрешит — опечатка не поймается
const statusLiteral = "ok" as const; // "ok"
// statusLiteral = "fail"; // ошибка
type Result = "ok" | "fail";
const fixed: Result = "ok"; // явный union
| Ситуация | Вывод | Как сузить |
|---|---|---|
const x = "a" | string (для let) / литерал (для const в простых случаях) | as const или явный union |
["a", "b"] | string[] | as const → readonly tuple / union элементов |
fetch без схемы | unknown / any в legacy | type predicate, Zod |
| Объект конфига | широкие поля при аннотации : Config | satisfies Config — см. ниже |
Компилятор намеренно выбирает безопасное обобщение — широкий тип ожидаем. Задача разработчика — сузить контракт там, где важны конкретные литералы.
Сужение типов (narrowing)
Сужение типов (type narrowing) — процесс, при котором после проверки (if, switch, type predicate) компилятор сокращает union до одной ветки и разрешает доступ к полям этой ветки.
После проверки компилятор сужает union до конкретной ветки.
typeof, truthiness
function print(value: string | number): void {
if (typeof value === "string") {
console.log(value.toUpperCase());
return;
}
console.log(value.toFixed(2));
}
in для объектов
type Cat = { kind: "cat"; meow: () => void };
type Dog = { kind: "dog"; bark: () => void };
type Pet = Cat | Dog;
function speak(pet: Pet) {
if (pet.kind === "cat") {
pet.meow();
return;
}
pet.bark();
}
Discriminated union (дискриминируемое объединение)
Discriminated union — union объектов с общим полем-дискриминантом (часто kind, type, status), значение которого однозначно указывает ветку. Компилятор сужает тип по этому полю в if / switch.
type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; side: number };
type Shape = Circle | Square;
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2; // shape: Circle
case "square":
return shape.side ** 2; // shape: Square
}
}
Требования к хорошему discriminated union:
- Дискриминант — литеральный union (
"idle" | "loading", не простоstring). - В каждой ветке — разный набор полей, зависящий от дискриминанта.
- Обработка —
switch/ifс exhaustivedefault: never— см. ниже.
Практика в UI и async — Операторы и ветвления, Асинхронность.
Discriminated union и exhaustive check
Код ITЗагрузка примера кода…
Разбор:
- Поле
status— дискриминант: по нему TS знает, какие поля доступны в ветке. defaultсneverловит забытый вариант union при добавлении новогоstatus.
Type predicates (value is T)
Пользовательская проверка, после которой компилятор доверяет сужению:
Код ITЗагрузка примера кода…
Разбор:
- Сигнатура
value is Payment— type predicate: внутриif (isPayment(x))типx—Payment. - Отличие от
boolean: обычная функцияcheck(x): booleanне сужает тип аргумента. - Подробнее в ветвлениях и Асинхронность (ответ
fetch).
Assertion functions (asserts value is T)
Если проверка не прошла — функция бросает; если вернулась — тип сужен:
function assertPayment(value: unknown): asserts value is Payment {
if (!isPayment(value)) {
throw new Error("Expected Payment");
}
}
function processWebhook(body: unknown): void {
assertPayment(body);
console.log(body.amount); // Payment
}
Разбор:
asserts value is Payment— компилятор считает: после вызова безthrowаргумент точноPayment.- Удобно в начале обработчика, когда дальше много кода и не хочется оборачивать всё в
if.
Пример диагностики до сужения:
error TS18046: 'raw' is of type 'unknown'.
После if (!isPayment(raw)) throw … или assertPayment(raw) ошибка исчезает.
Utility types
Встроенные преобразования над типами. Один и тот же User удобен, чтобы увидеть сценарий → utility:
| Сценарий | Utility | Пример |
|---|---|---|
| PATCH API, не все поля обязательны | Partial<T> | Partial<User> |
| форма/импорт: всё заполнено | Required<T> | Required<User> (в т.ч. бывший email?) |
| конфиг после загрузки, без мутаций | Readonly<T> | Readonly<User> |
| виджет сайдбара | Pick<T, K> | Pick<User, "name" | "role"> |
POST без серверного id | Omit<T, K> | Omit<User, "id"> |
кэш id → пользователь | Record<K, V> | Record<string, User> |
роли без admin | Exclude<T, U> | Exclude<User["role"], "admin"> → "user" |
| только пересечение с набором | Extract<T, U> | Extract<User["role"], "admin" | "root"> → "admin" |
убрать null/undefined из поля | NonNullable<T> | NonNullable<User["email"]> → string |
Базовая таблица:
| Utility | Назначение |
|---|---|
Partial<T> | Все поля опциональны |
Required<T> | Все поля обязательны |
Readonly<T> | Все поля readonly |
Pick<T, K> | Подмножество полей |
Omit<T, K> | Все поля, кроме перечисленных |
Record<K, V> | Словарь ключ → значение |
Exclude<T, U> | Убрать из union типы, совместимые с U |
Extract<T, U> | Оставить в union только совместимые с U |
NonNullable<T> | Убрать null и undefined |
interface User {
id: string;
name: string;
email?: string;
role: "admin" | "user";
}
type UserPatch = Partial<Pick<User, "name">>;
type NewUserRequest = Omit<User, "id">;
type PublicUser = Omit<User, "role">;
type RoleMap = Record<User["role"], string[]>;
type NonAdminRole = Exclude<User["role"], "admin">; // "user"
type ValidEmail = NonNullable<User["email"]>; // string
Полный список и продвинутые (ReturnType, Parameters, Awaited, mapped types) — Справочник — утилитарные и расширенные типы. Связки generics + Omit + keyof + literal union — дженерики.
Exclude, Extract и NonNullable
Exclude<T, U> вырезает из union T всё, что совместимо с U. Удобно для "все ответы API, кроме успеха" или "все роли, кроме admin".
Extract<T, U> оставляет только пересечение: что из T подходит под U.
NonNullable<T> убирает null и undefined — часто после проверки optional-поля.
Код ITЗагрузка примера кода…
Разбор:
Excludeработает на уровне типов (до runtime); сужение внутриlogError— на уровне значений через дискриминантstatus— ветвления.- После
if (e.status === "validation_error")вelseостаётся толькоServerErrorResponse— доступ кe.codeбезопасен. - Для успешной ветки используйте отдельный тип
OkResponseилиExtract<ApiResponse, OkResponse>.
Связанный выбор аргументов (ключ → тип значения, событие → payload) — дженерики §связанный выбор.
Где выполняется проверка типов
| Этап | Инструмент | Что проверяется |
|---|---|---|
| Редактирование | tsserver / LSP | Файлы по tsconfig, подсказки, ошибки в реальном времени |
| Сборка / CI | tsc, tsc --noEmit | Весь граф проекта (или references в monorepo) |
| Runtime | JavaScript | Типов нет — только значения |
Аннотации : string, interface, дженерики стираются при emit. Если в dist/ попал старый JS без пересборки, runtime может вести себя иначе, чем показывает IDE — всегда синхронизируйте сборку и typecheck в CI — Архитектура компиляции TypeScript и runtime.
as const и satisfies
as const
as const (const assertion) — утверждение, что значение неизменяемо и литералы нужно сохранить максимально узкими: readonly, строковые/числовые литералы вместо string/number.
const routes = ["home", "profile", "settings"] as const;
type Route = (typeof routes)[number]; // "home" | "profile" | "settings"
const config = { retries: 3, mode: "strict" } as const;
// config.retries: 3, config.mode: "strict", всё readonly
Без as const массив routes получил бы тип string[] вместо кортежа литералов.
satisfies
satisfies — проверяет, что значение соответствует типу, но не расширяет вывод полей до этого типа. IDE сохраняет узкие литералы и автодополнение.
type Palette = Record<string, string | readonly [number, number, number]>;
const palette = {
red: [255, 0, 0],
green: "#00ff00",
} satisfies Palette;
// palette.green — string (не union всех значений Palette)
const g = palette.green.toUpperCase();
| Конструкция | Проверка формы | Вывод типа переменной |
|---|---|---|
: Palette | да | широкий Palette |
satisfies Palette | да | узкий, как у литерала |
as const | нет (только сужение литералов) | максимально узкий readonly |
С satisfies форма проверяется, автодополнение по полям остаётся узким. Широкая аннотация : Palette расширила бы тип green до string | readonly [...].
typeof и keyof
const defaults = {
retries: 3,
timeoutMs: 5000,
} as const;
type Defaults = typeof defaults;
// { readonly retries: 3; readonly timeoutMs: 5000 }
type DefaultKey = keyof typeof defaults; // "retries" | "timeoutMs"
Полезно, когда тип должен следовать за значением конфигурации без дублирования.
Частые ошибки
| Ошибка | Причина | Что делать |
|---|---|---|
Type 'X' is not assignable to type 'Y' | Контракт не совпадает с данными | Пройти цепочку API → DTO (объект с API) → domain; исправить тип или значение |
Object is possibly 'undefined' | strictNullChecks | Проверка, ??, optional chaining |
Property 'x' does not exist on type | Union не сужен | switch по дискриминанту, in, typeof |
Везде any ради быстрой сборки | Отключена проверка | unknown, типы API, рекомендации |
| Дублирование структуры | Нет общего type | interface / Pick / общий модуль types/ |
Практика
- Опишите
User,Admin,Guestс полем-дискриминантомkindи объедините вAccount. НапишитеgetDisplayName(account: Account)сswitch. - Смоделируйте загрузку API как
LoadState(idle / loading / success / error) и функциюrender(state)с exhaustivedefault. - Для объекта конфигурации используйте
satisfiesи убедитесь, что IDE подсказывает конкретные поля. - Возьмите JSON из
fetchкакunknownи напишитеparseUser(raw: unknown): Userс проверками (безany). - Сформируйте
PublicUserчерезOmitиUserPatchчерезPartial<Pick<…>>. - Опишите
ApiResponseиз трёх веток и типErrorResponse = Exclude<ApiResponse, OkResponse>; напишитеlogErrorс сужением поstatus. - Напишите
isUser(value: unknown): value is UserиassertUser(value: unknown): asserts value is User.
Смежные статьи
- Переменные и константы —
let/const,readonly, деструктуризация - Операторы и ветвления —
switchи discriminated unions - Функции — сигнатуры, overloads
- Дженерики —
Array<T>,Promise<T> - Объекты и классы — модификаторы, наследование
- Рекомендации — strict, валидация внешних данных
- Справочник раздела — маршрут по Справочник по TypeScript
- Обзор в контексте JS: Обзор TypeScript в JS