Основы TypeScript: практическое руководство для разработчиков JavaScript
TypeScript для разработчиков JavaScript: практическое руководство — основные типы, tsconfig, режим строгости, а также пошаговый план миграции, делающий код более безопасным для последующих изменений.
Источники: TypeScript for JavaScript Developers: A Practical Beginner’s Guide
Если вы уже знаете JavaScript, освоение TypeScript кажется не столько изучением совершенно нового языка, сколько расширением того, что вы уже понимаете.
Типоговор является по сути JavaScript с дополненной к нему системой типов.
Вы продолжаете работать с переменными, функциями, массивами, объектами, классами, обещаниями, async/await, модулями и практически со всем остальным, что вам уже знакомо. TypeScript предоставляет набор инструментов, которые помогают выявлять ошибки на ранней стадии, ещё до того, как ваш код будет запущен в браузере или на сервере.
В этом руководстве рассматриваются концепции TypeScript, наиболее важные для разработчиков, уже пишущих на JavaScript.
Что такое TypeScript?
TypeScript — это язык, построенный на основе JavaScript.
В большинстве случаев любая программа на JavaScript, которую вы пишете, также является допустимым кодом на TypeScript. Типовой язык TypeScript добавляет возможность статической проверки типов, и в конечном итоге он компилируется в обычный JavaScript, который работает в браузерах и на Node.js.
Возьмем в пример этот простой фрагмент кода на JavaScript:
function add(a, b) {
return a + b;
}
При переписывании на TypeScript та же функция может указывать, какие типы значений она принимает:
function add(a: number, b: number): number {
return a + b;
}
Разберем это подробнее:
a: numberтребует, чтобыaбыл числом.b: numberтребует, чтобыbбыл числом.- Заключение
: numberуказывает на то, что возвращаемое значение функции — это число.
Благодаря этим аннотациям TypeScript может выявить некорректный вызов функции еще до начала её выполнения:
add(10, 20); // Correct
add("10", "20"); // TypeScript error
В обычном JavaScript вызов функции с строковыми аргументами молча вернёт "1020", поскольку оператор плюс будет соединять строки вместо того, чтобы складывать числа. TypeScript заранее выявляет такое нежелательное поведение.
Зачем использовать TypeScript?
Гибкость JavaScript — это сильная сторона, но она также может привести к скрытым ошибкам.
Возьмём в пример эту функцию:
function calculateDiscount(price, percentage) {
return price - price * percentage / 100;
}
Правильный вызов работает так, как ожидается:
calculateDiscount(1000, 10);
Но ничто не мешает вызвать её вот так:
calculateDiscount("1000", "ten");
Проблема проявляется только тогда, когда код фактически выполняется.
С использованием TypeScript можно указать типы, которые ожидает функция:
function calculateDiscount(
price: number,
percentage: number
): number {
return price - price * percentage / 100;
}
Теперь TypeScript сразу же фиксирует неверные аргументы, без необходимости сначала запускать код.
Среди основных преимуществ, которые это приносит, можно выделить:
- Обнаружение ошибок на этапе написания кода
- Улучшенная поддержка автодополнения в редакторе
- Прощее и более безопасное рефакторинг
- Более четкая структура функций и объектов
- Более эффективное сотрудничество над крупными проектами
- Типы, выполняющие роль встроенной документации
Преимущества TypeScript становятся особенно очевидными, когда проект вырастает за пределы нескольких файлов или в нем участвует более одного разработчика.
Установка TypeScript
TypeScript можно установить глобально с помощью:
npm install -g typescript
Чтобы убедиться в версии, установленной на системе, выполните:
tsc --version
Затем создайте файл с названием:
app.ts
Добавьте в него небольшой фрагмент кода на TypeScript:
const message: string = "Hello TypeScript";
console.log(message);
Скомпилируйте файл с помощью:
tsc app.ts
В результате получится скомпилированный JavaScript-код:
app.js
Результат можно запустить непосредственно с помощью Node.js:
node app.js
В производственных средах инструменты и фреймворки вроде React, Next.js, Angular и NestJS обычно автоматически выполняют этот шаг компиляции за вас.
Файл tsconfig.json
Большинство проектов на TypeScript используют файл tsconfig.json для настройки компилятора.
Его можно сгенерировать следующим образом:
tsc --init
Минимальная конфигурация может выглядеть так:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
}
}
Вот некоторые из наиболее важных параметров:
target
Этот параметр определяет версию JavaScript, которую выводит компилятор.
"target": "ES2020"
module
Он задаёт формат модулей, используемый в результате компиляции.
"module": "ESNext"
strict
Включение этой опции активирует более строгую проверку типов.
"strict": true
Для любого нового проекта настоятельно рекомендуется оставлять режим строгости включённым.
rootDir
Это указывает компилятору, где находятся исходные файлы TypeScript.
"rootDir": "./src"
outDir
Это определяет место, куда должен быть сохранён скомпилированный JavaScript.
"outDir": "./dist"
Основные типы
В TypeScript предустановлено несколько примитивных типов, которые вам уже знакомы.
Строка
let username: string = "Vijeet";
Число
let experience: number = 10;
TypeScript не различает целые числа и числа с плавающей точкой; оба относятся к типу number.
let age: number = 35;
let price: number = 999.99;
Логическое значение
let isActive: boolean = true;
Null и Undefined
let emptyValue: null = null;
let missingValue: undefined = undefined;
В режиме строгой проверки вам потребуется более тщательно обрабатывать значения null и undefined.
Определение типа
Вам не обязательно вручную аннотировать каждое значение.
TypeScript часто может определить тип переменной на основе того, что ей присвоено.
let city = "Ahmedabad";
Здесь TypeScript автоматически распознаёт city как строку.
Попытка переиспользовать его в другом формате приведёт к ошибке:
city = 100;
Здесь применяется та же логика:
let total = 500;
TypeScript считает, что total содержит число.
Использование автоматического определения типов делает код менее загруженным. Оставляйте явные аннотации типов там, где они действительно повышают ясность, например для параметров функций, структур ответов API и более сложных объектных структур.
Массивы
Вот простой массив в JavaScript:
const skills = ["JavaScript", "React", "Node.js"];
В TypeScript можно указать тип элементов массива:
const skills: string[] = [
"JavaScript",
"React",
"Node.js"
];
Это также можно сделать с использованием генерической синтаксиса:
const skills: Array<string> = [
"JavaScript",
"React",
"Node.js"
];
То же самое применимо к числовым массивам:
const scores: number[] = [75, 82, 91];
TypeScript блокирует любые попытки вставить значение неправильного типа:
scores.push(95); // Correct
scores.push("ninety"); // Error
Объекты
Можно задать явную структуру обычному JavaScript-объекту.
const user: {
name: string;
age: number;
isAdmin: boolean;
} = {
name: "Vijeet",
age: 35,
isAdmin: true
};
Если свойство отсутствует или имеет неправильный тип, TypeScript сигнализирует об этом как о ошибке.
const user: {
name: string;
age: number;
} = {
name: "Vijeet"
};
Здесь в объекте отсутствует необходимое свойство age.
Когда нужно использовать одну и ту же структуру объекта в нескольких местах, интерфейсы или псевдонимы типов более удобны, чем записывать структуру каждый раз вручную.
Интерфейсы
Интерфейс определяет структуру, которую должен иметь объект.
interface User {
id: number;
name: string;
email: string;
isActive: boolean;
}
После определения этот интерфейс можно использовать повторно где угодно:
const user: User = {
id: 1,
name: "Vijeet",
email: "vijeet@example.com",
isActive: true
};
Интерфейсы бывают полезны в таких ситуациях, как:
- описание сохранённых данных пользователя
- моделирование элемента каталога
- проверка полей, введённых в форму
- формирование данных, возвращаемых по результатам API-запроса
- определение типов параметров, передаваемых в компонент
- представление строки из таблицы базы данных
Например:
interface Product {
id: number;
title: string;
price: number;
}
Функция может принимать объект типа Product в качестве параметра:
function displayProduct(product: Product): void {
console.log(`${product.title}: ₹${product.price}`);
}
Необязательные свойства
Некоторые свойства объекта могут отсутствовать.
Чтобы обозначить их, добавляют вопросительный знак после имени свойства:
interface User {
id: number;
name: string;
phone?: string;
}
Оба приведённых ниже объекта соответствуют этому интерфейсу:
const userOne: User = {
id: 1,
name: "Amit"
};
const userTwo: User = {
id: 2,
name: "Neha",
phone: "9876543210"
};
Поскольку phone является необязательным, его тип становится:
string | undefined
Это означает, что перед использованием его необходимо проверить наличие:
if (userTwo.phone) {
console.log(userTwo.phone);
}
Псевдонимы типов
Псевдоним типа позволяет присвоить повторно используемое имя любому типу.
type UserId = number;
Затем этот псевдоним можно использовать в качестве типа:
const id: UserId = 101;
Псевдонимы типов особенно полезны при описании объединений или более сложных комбинаций типов.
type Status = "pending" | "approved" | "rejected";
С использованием этого псевдонима допускаются только три определенных строки:
let applicationStatus: Status = "pending";
Любые другие значения вызывают ошибку:
applicationStatus = "completed";
Интерфейсы против псевдонимов типов
И интерфейсы, и псевдонимы типов могут моделировать структуру объекта.
Вот версия с интерфейсом:
interface Customer {
name: string;
email: string;
}
А вот эквивалентная версия с псевдонимом типа:
type Customer = {
name: string;
email: string;
};
Как краткое руководство для новичков:
- Используйте
interface, когда описываете объекты или структуры классов. - Используйте
type, когда работаете с объединениями типов, псевдонимами для примитивов, кортежами или более сложными комбинированными типами.
Однако это не строгое правило — во многих случаях оба подхода работают одинаково хорошо.
Объединенные типы
Объединенный тип позволяет значению принимать один из нескольких возможных типов.
let userId: string | number;
Оба этих присваивания являются допустимыми:
userId = 101;
userId = "USR-101";
Объединенные типы полезны, когда данные из реального мира не всегда соответствуют одному фиксированному формату.
function printId(id: string | number): void {
console.log(id);
}
Прежде чем вызывать метод, существующий только у одного из возможных типов, сначала необходимо ограничить диапазон значений:
function printId(id: string | number): void {
if (typeof id === "string") {
console.log(id.toUpperCase());
} else {
console.log(id.toFixed(0));
}
}
Эта техника называется сужением типа.
Литеральные типы
Литеральные типы ограничивают переменную точным, заранее определенным набором значений.
type Theme = "light" | "dark" | "system";
Такое присваивание допустимо:
let selectedTheme: Theme = "dark";
Но это присваивание отклоняется:
selectedTheme = "blue";
Литеральные типы хорошо подходят для таких случаев, как:
- текущий статус записи
- уровень прав, присвоенных пользователю
- настройка визуальной темы
- визуальный стиль кнопки
- HTTP-глагол, используемый в запросе
- режим работы приложения
В качестве примера:
type UserRole = "admin" | "editor" | "customer";
Функции
Для параметров функций тип указывается сразу после их имени.
function greet(name: string): string {
return `Hello, ${name}`;
}
Тип возвращаемого значения функции указывается после закрывающей скобки списка параметров.
function multiply(a: number, b: number): number {
return a * b;
}
Если функция не возвращает значение, означьте ее с помощью void.
function logMessage(message: string): void {
console.log(message);
}
Необязательные параметры обозначаются с помощью ?:
function greetUser(
name: string,
title?: string
): string {
if (title) {
return `Hello, ${title} ${name}`;
}
return `Hello, ${name}`;
}
Значения по умолчанию ведут себя точно так же, как и в обычном JavaScript:
function calculateTax(
amount: number,
rate: number = 18
): number {
return amount * rate / 100;
}
Типизация функций-стрелок
Функции-стрелки можно аннотировать таким же образом.
const subtract = (
a: number,
b: number
): number => {
return a - b;
};
Вот более компактная форма:
const subtract = (
a: number,
b: number
): number => a - b;
Тип any
Присвоение типа any значению указывает TypeScript на то, чтобы полностью прекратить его проверку.
let data: any = "Hello";
data = 100;
data = true;
data = { name: "Vijeet" };
Хотя это может показаться удобным в первую очередь, чрезмерное использование any лишает нас большинства преимуществ TypeScript.
Возьмем этот пример:
function processData(data: any): any {
return data.someProperty.someMethod();
}
TypeScript не может ничего сделать, чтобы обнаружить ошибки в этой функции.
Используйте any в тех случаях, когда это действительно неизбежно — например, при постепенной конвертации кодовой базы на JavaScript или при работе с данными от сторонних поставщиков, у которых отсутствуют корректные определения типов.
Тип unknown
unknown предоставляет более безопасный способ представления значений, тип которых неизвестен заранее.
let value: unknown;
Как и any, он принимает любые значения:
value = "Hello";
value = 100;
value = true;
Но в отличие от any, TypeScript заставляет вас сужать тип перед его фактическим использованием:
if (typeof value === "string") {
console.log(value.toUpperCase());
}
Поэтому unknown идеально подходит для:
- Данных, поступающих из внешних API
- Значений, парсируемых из JSON
- Объектов ошибок, попадающих в блок try/catch
- Данных, предоставляемых пользователями
- Любого контента, форма которого ещё не определена
Утверждения типов
Бывают случаи, когда у вас есть больше информации о значении, чем TypeScript может определить самостоятельно.
Утверждение типа позволяет указать компилятору, как обрабатывать это значение.
const input = document.getElementById(
"email"
) as HTMLInputElement;
После утверждения вы можете обращаться к свойствам, специфичным для этого типа:
console.log(input.value);
Имейте в виду, что утверждение ничего не меняет во время выполнения — оно лишь влияет на то, как TypeScript интерпретирует значение во время компиляции.
Поэтому следует использовать утверждения осторожно и только тогда, когда вы уверены в реальной структуре данных.
Туплы
Тупл — это массив с фиксированным количеством позиций, где каждая позиция имеет свой определенный тип.
let userEntry: [number, string];
userEntry = [1, "Vijeet"];
Здесь первая позиция должна содержать число, а вторая — строку.
Следующий пример приведет к ошибке:
userEntry = ["Vijeet", 1];
Туплы хорошо подходят для небольших данных фиксированной структуры или парных значений:
type Coordinate = [number, number];
const location: Coordinate = [23.0225, 72.5714];
Когда данные становятся более сложными или требуют описательных имен полей, простые объекты обычно представляются более понятными.
Enum
Enum позволяет определить фиксированный набор констант с именами.
enum OrderStatus {
Pending,
Processing,
Shipped,
Delivered
}
К ним можно обращаться следующим образом:
let status: OrderStatus = OrderStatus.Processing;
Присвоение enum строковых значений часто улучшает читаемость:
enum PaymentStatus {
Pending = "pending",
Paid = "paid",
Failed = "failed"
}
Тем не менее многие пользователи TypeScript предпочитают вместо этого типы-объединения, особенно для более простых сценариев:
type PaymentStatus =
| "pending"
| "paid"
| "failed";
Типы-объединения обычно приводят к меньшему объему генерируемого JavaScript и являются надежным стандартом для большинства кодов фронт-энда.
Классы
TypeScript расширяет обычные классы JavaScript с проверкой типов.
class Employee {
name: string;
salary: number;
constructor(name: string, salary: number) {
this.name = name;
this.salary = salary;
} getAnnualSalary(): number {
return this.salary * 12;
}
}
Создание экземпляра класса выглядит так же, как и в JavaScript:
const employee = new Employee("Rahul", 50000);
console.log(employee.getAnnualSalary());
Модификаторы доступа также являются частью синтаксиса классов в TypeScript.
class BankAccount {
public accountHolder: string;
private balance: number;
constructor(accountHolder: string, balance: number) {
this.accountHolder = accountHolder;
this.balance = balance;
} public getBalance(): number {
return this.balance;
}
}
Основные модификаторы:
public: видим с любой точкиprivate: видим только внутри самого классаprotected: видим внутри класса и всех его подклассовreadonly: может быть установлен один раз, но не может быть переопределен позже
Генерики
Генерики позволяют писать гибкий, повторно используемый код, сохраняющий полную типобезопасность при работе с разными типами данных.
Возьмите эту функцию в качестве отправной точки:
function returnValue(value: any): any {
return value;
}
Поскольку она использует any, TypeScript не может сообщить ничего о результатах её работы.
Переписывание кода с использованием генерического параметра решает эту проблему:
function returnValue<T>(value: T): T {
return value;
}
Теперь тип возвращаемого значения совпадает с тем, что было передано:
const text = returnValue<string>("Hello");
const count = returnValue<number>(100);
Во многих случаях TypeScript может автоматически определить генерический тип, поэтому не нужно его явно указывать:
const text = returnValue("Hello");
const count = returnValue(100);
Генерики постоянно используются при работе с массивами, структурами ответов API, повторно используемыми компонентами интерфейса, пользовательскими хуками и вспомогательными утилитами.
function getFirstItem<T>(items: T[]): T | undefined {
return items[0];
}
Используется так:
const firstNumber = getFirstItem([10, 20, 30]);
const firstName = getFirstItem(["Amit", "Neha"]);
Обещания и асинхронные функции
Функции, объявленные с ключевым словом async, всегда возвращают обещания.
async function getUsername(): Promise<string> {
return "Vijeet";
}
Асинхронная функция, возвращающая объект пользователя, может выглядеть так:
interface User {
id: number;
name: string;
}
async function getUser(): Promise<User> {
return {
id: 1,
name: "Vijeet"
};
}
А для списка пользователей тип возвращаемого значения нужно поместить в массив:
async function getUsers(): Promise<User[]> {
return [
{ id: 1, name: "Vijeet" },
{ id: 2, name: "Rahul" }
];
}
Присвоение результатам API соответствующих типов таким образом защищает остальную часть вашего кодового базиса от ошибок на последующих этапах.
Определение типов ответов API
Представьте конечную точку, возвращающую записи о продуктах:
interface Product {
id: number;
title: string;
price: number;
}
Вы можете обернуть вызов fetch в функцию, в которой указан тип её возвращаемого значения:
async function fetchProducts(): Promise<Product[]> {
const response = await fetch("/api/products");
if (!response.ok) {
throw new Error("Unable to fetch products");
} const data: Product[] = await response.json(); return data;
}
Есть момент, который стоит запомнить: TypeScript не может проверять эти данные после того, как приложение начнёт работать.
Эта строка:
const data: Product[] = await response.json();
только указывает компилятору рассматривать обработанный ответ как Product[] — она не подтверждает, что сервер действительно вернул объекты такой структуры.
В приложениях, где критически важна корректность, разработчики часто используют TypeScript вместе с библиотекой проверки на этапе выполнения, такой как Zod, чтобы устранить этот недостаток.
Работа с элементами DOM
Типы элементов браузера встроены в TypeScript.
const button = document.querySelector(
"#submit-button"
);
Компилятор знает, что этот запрос может вернуть пустой результат, поэтому тип результата включает null наряду с типом элемента.
Это означает, что перед использованием необходимо учитывать возможность отсутствия элемента:
if (button) {
button.addEventListener("click", () => {
console.log("Button clicked");
});
}
Если вам нужен более конкретный тип элемента, вы можете его проверить:
const emailInput = document.querySelector(
"#email"
) as HTMLInputElement | null;
Затем считайте его значение после подтверждения наличия:
if (emailInput) {
console.log(emailInput.value);
}
TypeScript не заменяет проверку во время выполнения
Этот момент требует особого внимания, особенно для разработчиков, переходящих с JavaScript.
Проверки в TypeScript происходят только на этапе разработки и компиляции. Как только ваш код скомпилируется в JavaScript, все аннотации типов исчезают.
Возьмем эту функцию:
function double(value: number): number {
return value * 2;
}
После компиляции она превращается примерно в следующее:
function double(value) {
return value * 2;
}
В этот момент не остается никаких следов исходной информации о типах, которая могла бы что-либо обеспечить.
В результате TypeScript не может гарантировать следующее:
- Что API действительно возвращает корректно сформированные данные
- Что пользователь ввёл допустимое значение
- Что запись в базе данных соответствует ожидаемой структуре
- Что сервис третьей стороны соблюдает свой документированный контракт
Любые данные, поступающие извне вашего кода, всё равно требуют проверки во время выполнения программы.
Миграция существующего проекта JavaScript
Преобразование кодовой базы JavaScript в TypeScript не обязательно должно происходить за один раз путём полной переработки.
Пошаговая миграция, как правило, работает лучше на практике.
Шаг 1: Установка TypeScript
npm install --save-dev typescript
Шаг 2: Создание файла tsconfig.json
npx tsc --init
Шаг 3: Временное использование JavaScript
{
"compilerOptions": {
"allowJs": true,
"checkJs": false
}
}
Шаг 4: Постепенное переименование файлов
Измените файл примерно так:
utils.js
на:
utils.ts
А для компонентов React преобразуйте:
Button.jsx
в:
Button.tsx
Шаг 5: Исправление ошибок по одному файлу за раз
Полезно начать с вспомогательных функций, общих моделей данных и более мелких компонентов, оставив более сложную логику приложения на позже.
Такой поэтапный подход является одним из главных практических преимуществ TypeScript при его внедрении в существующий проект.
Распространенные ошибки, которые допускают разработчики JavaScript
Использование any везде
const user: any = getUser();
Это может скрыть немедленные замечания компилятора, но в то же время устранить всю проверку типов.
Лучшим подходом является определение реального интерфейса:
interface User {
id: number;
name: string;
}
Добавление типов к каждой переменной
Нет необходимости писать это:
const name: string = "Vijeet";
const count: number = 10;
const active: boolean = true;
потому что механизм вывода типов самостоятельно определяет эти типы:
const name = "Vijeet";
const count = 10;
const active = true;
Оставляйте явные аннотации для тех случаев, когда они действительно способствуют большей ясности.
Игнорирование null
Этот код может сломаться во время выполнения:
const element = document.querySelector("#app");
element.innerHTML = "Hello";
Элемент, к которому производится запрос, может просто отсутствовать на странице.
Лучше защититься от такой возможности:
const element = document.querySelector("#app");
if (element) {
element.innerHTML = "Hello";
}
Использование утверждений типов для сокрытия проблем
Писать что-то подобное рискованно:
const user = apiResponse as User;
Утверждение не проверяет ничего в отношении реального ответа API — оно просто просит компилятор поверить вашим словам.
Рассмотрение TypeScript как отдельной среды выполнения
Браузер не выполняет TypeScript напрямую. Прежде чем он будет запущен, он сначала компилируется в обычный JavaScript.
Это означает, что все, что вы уже знаете о JavaScript, по-прежнему применимо.
Практический пример
Рассмотрим простой корзину покупок, написанную так, как вы обычно создали бы её на JavaScript, но теперь с добавлением типов TypeScript.
interface CartItem {
id: number;
name: string;
price: number;
quantity: number;
}
function calculateCartTotal(
items: CartItem[]
): number {
return items.reduce((total, item) => {
return total + item.price * item.quantity;
}, 0);
}
const cart: CartItem[] = [
{
id: 1,
name: "Keyboard",
price: 2500,
quantity: 1
},
{
id: 2,
name: "Mouse",
price: 1200,
quantity: 2
}
];
const total = calculateCartTotal(cart);
console.log(`Cart total: ₹${total}`);
Благодаря этому функция теперь защищена от некорректных данных в корзине.
Например, следующий фрагмент кода не сможет быть скомпилирован:
const invalidCart: CartItem[] = [
{
id: 1,
name: "Keyboard",
price: "2500",
quantity: 1
}
];
Проблема в том, что переменная price задана как строка, хотя должна быть числом.
Должен ли каждый проект на JavaScript использовать TypeScript?
Не всегда.
Обычный JavaScript по-прежнему отлично подходит для таких случаев, как:
- Небольшие эксперименты
- Простые скрипты
- Быстрые прототипы
- Базовые лендинг-страницы
Типскрипт обычно приносит наибольшую пользу в таких ситуациях:
- Большие фронтенд-приложения
- Кодовые базы React и Next.js
- Бэкенд-сервисы Node.js
- Кодовые базы, используемые несколькими командами
- Долговечные продукты
- Проекты, работающие с сложными структурами данных
- Приложения, создаваемые и обслуживаемые несколькими разработчиками
В общем, чем больше и дольше существует проект, тем большую пользу вы получаете от использования TypeScript.
Заключение
Типскрипт не является заменой JavaScript — он улучшает процесс написания кода на JavaScript, добавляя дополнительный уровень безопасности.
Если вы пришли из мира JavaScript, у вас уже есть большая часть необходимых знаний:
- Переменные
- Функции
- Объекты
- Массивы
- Классы
- Обещания
- Модули
- Асинхронный код
Остаётся изучить в основном то, как представлять структуру данных.
Хорошая отправная точка включает в себя:
- Примитивные типы
- Типы параметров и возвращаемых значений для функций
- Интерфейсы
- Типы объединения
- Необязательные свойства
- Генерики
- Типизированные ответы от API
Не пытайтесь сразу освоить все сложные функции. Начните с аннотирования обычного JavaScript, позволяя потребностям ваших реальных проектов определять следующие шаги в обучении.
Как только TypeScript станет частью вашей повседневной работы, возвращение к обычному, нетипизированному JavaScript может показаться неожиданно рискованным.