Начало работы
Hello World и компиляция
Файлы TypeScript используют расширение .ts. Компилятор tsc транслирует TS в JS, стирая все аннотации типов во время выполнения. Используйте --strict для максимальной type safety. ts-node или bun могут запускать .ts файлы напрямую без отдельного этапа компиляции.
// hello.ts
const message: string = "Hello, TypeScript!";
console.log(message);
// Compile to JavaScript (type annotations erased):
// tsc hello.ts -> hello.js
// tsc --strict hello.ts // enable all strict checks
// tsc --watch hello.ts // recompile on change
// Run directly with ts-node or bun:
// ts-node hello.tstsconfig.json
tsconfig.json настраивает компилятор TypeScript. 'strict: true' включает noImplicitAny, strictNullChecks, strictFunctionTypes и многое другое. 'target' управляет выходной версией JS. 'esModuleInterop' включает импорт по умолчанию из модулей CommonJS, таких как встроенные модули Node.
{
"compilerOptions": {
"target": "ES2020", // JS version to emit
"module": "ESNext", // module system
"strict": true, // enable all strict checks
"outDir": "./dist", // output directory
"rootDir": "./src", // source root
"esModuleInterop": true, // allow default imports from CJS
"skipLibCheck": true, // skip .d.ts type checking
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Аннотации типов и вывод типов
Аннотации типов явно указывают тип переменной. TypeScript также может выводить типы из значений. Используйте явные аннотации для сигнатур функций и публичных API; полагайтесь на вывод типов для локальных переменных. Избегайте 'any' — это полностью отключает проверку типов.
// Explicit type annotations
let count: number = 0;
const name: string = "Alice";
let isDone: boolean = true;
let ids: number[] = [1, 2, 3];
let tuple: [string, number] = ["age", 30];
// Type inference (let TS figure it out)
let age = 30; // inferred as number
let items = [1, 2, 3]; // inferred as number[]
let mixed = [1, "a"]; // inferred as (string | number)[]
// any disables type checking (avoid!)
let anything: any = 42;
anything = "string"; // no errorПроверки строгого режима
Строгий режим включает критически важные проверки: strictNullChecks (null/undefined нельзя присвоить другим типам), noImplicitAny (параметры должны иметь типы), strictPropertyInitialization (поля класса должны быть инициализированы). Используйте '!' (определённое присваивание), когда вы уверены, что поле будет установлено позже.
// strictNullChecks: null/undefined not assignable to other types
let n: string = null; // Error in strict mode
// noImplicitAny: must annotate parameters
function greet(name) { } // Error: implicit any
// strictPropertyInitialization
class User {
name: string; // Error: not initialized
constructor() {}
}
// Fix: initialize or use definite assignment
class Fixed {
name!: string; // definite assignment assertion
age: number = 0;
}Файлы объявлений (.d.ts)
Файлы объявлений (.d.ts) предоставляют типы для библиотек JavaScript без определений TypeScript. 'declare' сообщает компилятору, что переменная/функция существует во время выполнения. Используйте пакеты @types из DefinitelyTyped для популярных библиотек (например, @types/node, @types/react).
// types.d.ts - type declarations only, no implementation
declare module "my-lib" {
export function greet(name: string): string;
export const version: string;
}
// global.d.ts - extend global scope
declare global {
interface Window {
myApp: { version: string };
}
}
// Usage in .ts files:
// import { greet } from "my-lib"; // now typed
// Install @types packages: npm i -D @types/node @types/reactБазовые типы
Примитивы и специальные типы
Примитивы TypeScript: string, number, boolean, bigint, symbol. 'void' указывает, что функция не возвращает значение. 'never' представляет значения, которые никогда не возникают — функции, которые выбрасывают исключение или выполняются бесконечно. Используйте 'never' для исчерпывающих проверок в switch.
let str: string = "hello";
let num: number = 42;
let bool: boolean = true;
let big: bigint = 100n;
let sym: symbol = Symbol("id");
// void: function returns nothing
function log(msg: string): void { console.log(msg); }
// never: function never returns
function fail(msg: string): never { throw new Error(msg); }
function infinite(): never { while (true) {} }Массивы и кортежи
Массивы используют синтаксис T[] или Array<T>. ReadonlyArray предотвращает мутации. Кортежи — массивы фиксированной длины с определёнными типами на каждой позиции — полезны для пар ключ-значение или CSV-подобных данных. Именованные кортежи улучшают читаемость с помощью названных позиций.
// Two syntaxes for arrays
let nums: number[] = [1, 2, 3];
let strs: Array<string> = ["a", "b"];
// ReadonlyArray (immutable)
const ro: ReadonlyArray<number> = [1, 2, 3];
// ro.push(4); // Error: not mutable
// Tuple (fixed length, known types)
let tuple: [string, number] = ["Alice", 30];
let name = tuple[0]; // string
let age = tuple[1]; // number
// Labeled tuple elements (TS 4.0+)
let entry: [name: string, age: number] = ["Bob", 25];Enum'ы
Enum'ы определяют набор именованных констант. Строковые enum'ы рекомендуются для отладки (значения читаемы в выводе). Числовые enum'ы поддерживают обратное отображение. 'const enum' удаляется при компиляции (встраивается) без накладных расходов во вре мя выполнения. Для простых случаев предпочитайте типы объединения.
// Numeric enum (default starts at 0)
enum Direction { Up, Down, Left, Right }
let d: Direction = Direction.Up; // 0
// String enum (recommended for readability)
enum Status {
Pending = "PENDING",
Success = "SUCCESS",
Failed = "FAILED",
}
// Reverse mapping (numeric only)
console.log(Direction[0]); // "Up"
// Const enum (inlined, no runtime object)
const enum Color { Red, Green, Blue }
let c = Color.Red; // compiles to: let c = 0;any vs unknown vs never
'any' отключает всю проверку типов — избегайте его. 'unknown' — типобезопасная альтернатива: вы должны сузить его (через typeof, instanceof) перед использованием. 'never' представляет значения, которые никогда не возникают, используется для исчерпывающей проверки в switch для отлова пропущенных случаев при компиляции.
// any: opt out of type checking (dangerous!)
let a: any = 42;
a = "string"; // OK
a.toUpperCase(); // OK (no check, may fail at runtime)
// unknown: type-safe alternative to any
let u: unknown = 42;
// u.toUpperCase(); // Error: unknown type
if (typeof u === "string") {
u.toUpperCase(); // OK after narrowing
}
// never: impossible value (exhaustiveness check)
type Shape = "circle" | "square";
function area(s: Shape) {
switch (s) {
case "circle": return Math.PI;
case "square": return 1;
default:
const _exhaustive: never = s; // Error if case missing
}
}Утверждения типа
Утверждения типа сообщают компилятору 'доверься мне, я знаю тип'. Используйте синтаксис 'as'. Утверждение non-null (!) сообщает TS, что значение не null/undefined. 'as const' делает все свойства readonly-литералами — полезно для объектов конфигурации и типов действий Redux. Утверждения не меняют поведение во время выполнения.
// as syntax (preferred, works in .tsx)
let val: unknown = "hello";
let len: number = (val as string).length;
// Non-null assertion (!)
let el = document.querySelector("#app")!;
el.innerHTML = "Hi"; // el is HTMLElement, not null
// Double assertion (for unsafe casts)
let value = "42" as unknown as number;
// const assertion (literal types)
const req = { method: "GET", url: "/api" } as const;
// req.method has type "GET" (not string)
// req is readonlyЛитеральные типы и типы объединения
Литеральные типы ограничивают значение конкретной строкой, числом или логическим значением. В сочетании с объединениями они создают точные типы вроде direction или HTTP-методов. Template literal типы (TS 4.1+) строят строковые типы из других типов — мощный инструмент для генерации типобезопасных ключей и имён событий.
// String literal types
let direction: "left" | "right" | "up" | "down";
direction = "left"; // OK
// direction = "sideways"; // Error
// Numeric literal types
let dice: 1 | 2 | 3 | 4 | 5 | 6;
dice = 4; // OK
// Boolean literal
let flag: true = true;
// Template literal types (TS 4.1+)
type Color = "red" | "blue";
type Size = "small" | "large";
type Variant = `${Size}-${Color}`;
// "small-red" | "small-blue" | "large-red" | "large-blue"Интерфейсы и объекты
Основы интерфейсов
Интерфейсы описывают форму объектов. '?' помечает необязательные свойства (могут быть undefined). 'readonly' предотвращает переприсваивание после инициализации. Интерфейсы существуют только на этапе компиляции — они удаляются из выходного JavaScript. Используйте их для определения контрактов для объектов и классов.
interface User {
id: number;
name: string;
email?: string; // optional property
readonly createdAt: Date; // immutable
}
const user: User = {
id: 1,
name: "Alice",
createdAt: new Date(),
};
// user.createdAt = new Date(); // Error: readonly
// user.email; // string | undefinedИндексные сигнатуры
Индексные сигнатуры разрешают объекты с произвольными ключами заданного типа. Все значения свойств должны быть совместимы с индексным типом. Полезно для словарей, кэшей и динамических данных. Комбинируйте с известными свойствами для типизированных конфигураций с дополнительными опциями.