FAQ Портал
Категории
Поиск
О нас
Контакты
UK
RU
EN
Главная
Технологии
Программирование
TypeScript
TypeScript
100 вопросов
Как установить TypeScript в проект?
•
npm i -D typescript.
•
npx tsc --init создаст tsconfig.json.
•
Добавь скрипты: tsc, tsc -w.
•
Для Node: npm i -D ts-node.
•
Проверь: npx tsc -v.
Что такое tsconfig.json и за что он отвечает?
•
Это конфигурация компилятора.
•
target/module определяют выходной JS.
•
strict включает строгие проверки.
•
include/exclude управляют файлами.
•
paths/baseUrl настраивают алиасы.
Чем отличаются type и interface?
•
interface расширяется через extends.
•
interface поддерживает declaration merging.
•
type удобен для union/intersection.
•
Для объектов чаще берут interface, но это не правило.
•
В реальности выбирай по задаче и стилю команды.
Что такое strict mode в TypeScript и почему его стоит включать?
•
strict включает набор строгих флагов.
•
Ловит ошибки с null/undefined и типами.
•
Улучшают автодополнение и рефакторинг.
•
Повышает качество кода на больших проектах.
•
Включай постепенно, если проект старый.
Что такое any и почему его стоит избегать?
•
any отключает проверку типов.
•
Ошибки переезжают в runtime.
•
Вместо any используй unknown, generics или точные типы.
•
Для миграции можно временно использовать any, но с планом убрать.
•
Можно ограничить через eslint/tsconfig.
Чем отличается unknown от any?
•
unknown безопаснее: нельзя использовать без проверки.
•
Требует narrowing (typeof, in, instanceof).
•
Подходит для внешних данных (JSON).
•
any — 'дырка' в типах.
•
С unknown ошибки ловятся на этапе компиляции.
Как типизировать результат JSON.parse?
•
JSON.parse возвращает any.
•
Используй unknown и валидируй структуру.
•
Сделай type guard или схему (zod).
•
После валидации — приведи к нужному типу.
•
Не делай слепой as YourType без проверки.
Что такое type narrowing и как он работает?
•
Это сужение типа в ветках кода.
•
Используй typeof для примитивов.
•
Используй in/instanceof для объектов/классов.
•
Пользовательские type guards тоже сужают тип.
•
Помогает писать код без лишних кастов.
Как написать type guard функцию?
•
Функция возвращает выражение вида x is T.
•
Внутри проверяй поля и типы.
•
Используй для unknown/union.
•
Держи проверки простыми и покрывай тестами.
•
Валидация схемой (zod) часто надёжнее.
Что такое union types и где они полезны?
•
Union: A | B.
•
Хорошо для ограниченных наборов значений.
•
Часто используют с дискриминирующим полем.
•
Требует narrowing перед доступом к специфичным полям.
•
Улучшает выразительность API.
Что такое intersection types и когда их использовать?
•
Intersection: A & B.
•
Объединяет свойства нескольких типов.
•
Удобно для композиций и миксинов.
•
Осторожно с конфликтующими полями.
•
Часто встречается в типах библиотек.
Что такое literal types и зачем они нужны?
•
Типы литералов: 'GET', 200, true.
•
Основа для union из конкретных значений.
•
Удобно для статусов, ролей, режимов.
•
Работают вместе с as const.
•
Помогают избежать опечаток.
Зачем нужен as const?
•
Делает литералы неизменяемыми и узкими.
•
Превращает массив в readonly tuple.
•
Полезно для конфигов и словарей.
•
Упрощает вывод типов.
•
Часто используется с satisfies.
Что такое satisfies и чем он лучше 'as'?
•
satisfies проверяет соответствие типу, но сохраняет вывод.
•
Не 'зажимает' значения как as.
•
Полезно для конфигов и маппингов.
•
Помогает ловить ошибки ключей/полей.
•
Доступно в TS 4.9+.
Как типизировать объект-словарь с фиксированными ключами?
•
Используй Record<K, V>.
•
K может быть union литералов.
•
Для частичных ключей — Partial<Record<...>>.
•
Для проверки без потери вывода — satisfies.
•
Для динамики — index signature.
Что такое index signature и когда он нужен?
•
{[key: string]: Value}.
•
Для объектов с неизвестными ключами.
•
Ограничивает тип всех значений.
•
Может конфликтовать с конкретными полями — аккуратно.
•
Иногда лучше Map<string, V>.
Как типизировать массив с фиксированной структурой (tuple)?
•
Tuple: [number, string].
•
Можно делать readonly tuple через as const.
•
Для именованных элементов: [id: string, value: number].
•
Удобно для пар key-value.
•
Для больших структур лучше interface.
Что такое generics и зачем они нужны?
•
Позволяют параметризовать типы.
•
Например: function first<T>(a: T[]): T.
•
Убирают дублирование кода.
•
Можно ограничивать T через extends.
•
Улучшают типизацию библиотек.
Как ограничивать generics через extends?
•
<T extends { id: string }>.
•
Тогда у T гарантированно есть id.
•
Можно ограничивать union'ом.
•
Для ключей используйте extends keyof.
•
Ограничения улучшают автодополнение.
Как типизировать функцию getProperty(obj, key)?
•
<T, K extends keyof T>(obj: T, key: K) => T[K].
•
keyof даёт набор ключей.
•
T[K] возвращает тип значения по ключу.
•
Работает и с optional полями.
•
Это канонический пример generics.
Что такое keyof и почему он полезен?
•
keyof T даёт union ключей типа.
•
Позволяет безопасно индексировать.
•
Удобен в утилитах Pick/Omit.
•
Помогает строить типобезопасные API.
•
Работает вместе с mapped types.
Что такое mapped types?
•
Это типы вида { [K in keyof T]: ... }.
•
Позволяют трансформировать поля.
•
На них основаны Partial/Required/Readonly.
•
Можно менять модификаторы: -? / +readonly.
•
Мощный инструмент для библиотек.
Как работает Partial<T> и когда его использовать?
•
Делает все поля optional.
•
Удобно для патч-объектов (update).
•
Опасность: теряется гарантия наличия полей.
•
Часто лучше Partial<Pick<T, ...>>.
•
Для формы ввода — хороший вариант.
В чём разница между Pick и Omit?
•
Pick берёт подмножество полей.
•
Omit исключает поля.
•
Удобно для DTO и публичных моделей.
•
Избегай дублирования структур.
•
Комбинируй с Partial/Required.
Что такое Record<K, V> и где он полезен?
•
Record создаёт объект с ключами K и значениями V.
•
Удобно для словарей и маппингов.
•
K может быть union'ом.
•
Для неполных ключей используй Partial<Record<...>>.
•
Для строгой проверки ключей — satisfies.
Как типизировать функции обратного вызова (callbacks)?
•
Опиши сигнатуру: type Fn = (x: number) => string.
•
Для событий — используй типы библиотеки (React, DOM).
•
Для async — Promise<...>.
•
Не забывай про optional параметры.
•
Делай возвращаемое значение явным.
Как типизировать Promise и async/await?
•
async функция возвращает Promise<T>.
•
Укажи тип результата: Promise<User>.
•
await раскрывает Promise.
•
Обрабатывай ошибки через try/catch.
•
Не возвращай any из async-цепочек.
Что такое overloads (перегрузки) функций?
•
Можно объявить несколько сигнатур.
•
Реализация одна, но типы разные.
•
Полезно для функций с разными режимами.
•
Перегрузки должны быть совместимы.
•
Иногда проще использовать union и narrowing.
Чем отличается type assertion (as) от реальной проверки типов?
•
as не проверяет runtime.
•
Он говорит компилятору: 'поверь'.
•
Может скрыть баги.
•
Лучше сначала валидировать данные.
•
Используй as только когда точно знаешь структуру.
Что такое non-null assertion (!) и почему он опасен?
•
x! говорит, что x не null/undefined.
•
Компилятор перестаёт ругаться.
•
В runtime может упасть, если ты ошибся.
•
Лучше проверка if (x) или optional chaining.
•
Используй редко и осознанно.
Как работает optional chaining (?.)?
•
Позволяет безопасно обращаться к вложенным полям.
•
obj?.a?.b вернёт undefined, если что-то отсутствует.
•
Работает с вызовом функций: fn?.().
•
Не заменяет бизнес-валидацию.
•
Удобно для UI и данных из API.
Как работает nullish coalescing (??)?
•
a ?? b берёт b только если a null/undefined.
•
Не путается с 0/''/false как ||.
•
Отлично для дефолтов.
•
Часто комбинируется с optional chaining.
•
Понимай разницу между || и ??.
Как типизировать ошибки в catch в строгом режиме?
•
В TS catch-переменная часто unknown.
•
Проверь: err instanceof Error.
•
Логируй безопасно: String(err).
•
Для библиотек делай свои error types.
•
Не предполагай структуру без проверки.
Что такое discriminated union и как его проектировать?
•
Union с полем-тегом: type: 'a' | 'b'.
•
В switch по тегу тип автоматически сужается.
•
Удобно для событий и состояния.
•
Добавляй exhaustive check (never).
•
Это один из лучших паттернов TS.
Как сделать exhaustive check в switch?
•
В default присвой переменную типа never.
•
Если появится новый вариант union — компилятор ругнётся.
•
Пример: const _exhaustive: never = x.
•
Помогает поддерживать код.
•
Особенно полезно в reducer'ах.
Как типизировать классы и их поля в TypeScript?
•
Указывай модификаторы: public/private/protected.
•
Объявляй поля заранее или в constructor.
•
Используй readonly для неизменяемых.
•
Параметр-свойства: constructor(private api: Api) {}.
•
Не злоупотребляй классами, если достаточно функций.
Что такое abstract class и interface: что выбрать?
•
interface описывает контракт без реализации.
•
abstract class может содержать общую реализацию.
•
В TS можно реализовать несколько interface, но наследовать один класс.
•
Для 'портов' и API обычно достаточно interface.
•
Abstract удобен для базовых компонентов/шаблонов.
Как типизировать this в методах и функциях?
•
У методов классов this выводится автоматически.
•
Для функций можно указать this-параметр: function f(this: X) {}.
•
Стрелочные функции берут this из внешнего контекста.
•
В callbacks часто теряется this — бинди или используй стрелки.
•
Правильная типизация ловит ошибки.
Как работает enum и почему часто советуют union вместо enum?
•
enum генерирует runtime-код (обычно).
•
Может усложнить bundle.
•
Union литералов проще и tree-shakable.
•
Если нужно runtime-значение — можно enum или const object.
•
const enum ускоряет, но опасен для библиотек.
Что такое const enum и в чём его риски?
•
const enum инлайнится в код.
•
Уменьшает runtime-накладные.
•
Может ломаться при сборке библиотек и разных настройках.
•
Не всегда совместим с babel/transpileOnly.
•
Часто лучше объект + as const.
Как типизировать функции высшего порядка (HOF)?
•
Обобщай входной и выходной тип.
•
Сохраняй сигнатуру через generics.
•
Для декораторов функций используй <T extends (...a: any[]) => any>.
•
Возвращай Parameters<T> и ReturnType<T>.
•
Это даёт сильную типизацию.
Что такое ReturnType и Parameters и когда они нужны?
•
ReturnType<F> берёт тип результата функции.
•
Parameters<F> берёт кортеж аргументов.
•
Полезно для обёрток и прокси.
•
Снижает дублирование.
•
Работает только с типами функций.
Как типизировать событийную систему (event emitter) безопасно?
•
Сделай map: EventName -> payload type.
•
on<K extends keyof Events>(name: K, cb: (p: Events[K]) => void).
•
emit аналогично.
•
Так ты избегишь ошибок типов в событиях.
•
Хороший паттерн для фронта и ноды.
Как типизировать API-клиент и ответы сервера?
•
Определи DTO типы для ответов.
•
Используй runtime-валидацию для внешних данных.
•
Для fetch делай функцию request<T>() возвращающую Promise<T>.
•
Никогда не доверяй серверу без проверок.
•
Логируй и обрабатывай ошибки статусов.
Как типизировать fetch и обработку JSON?
•
const res = await fetch(url).
•
Проверяй res.ok.
•
const data: unknown = await res.json().
•
Валидируй data и затем приводи к типу.
•
Таймауты/ретраи добавляй отдельно.
Как в TS правильно работать с DOM-типами?
•
Включи lib: ['DOM'].
•
Используй querySelector с generic: document.querySelector<HTMLDivElement>('...').
•
Проверяй на null.
•
Для событий используй MouseEvent/KeyboardEvent.
•
Не кастуй без необходимости.
Как типизировать addEventListener и обработчики?
•
element.addEventListener('click', (e) => { ... }).
•
e имеет тип MouseEvent (для клика).
•
Для window/document типы тоже выводятся.
•
Если нужно, уточняй target через instanceof.
•
Не используй any для событий.
Как типизировать React-компоненты на TypeScript?
•
Props через interface/type.
•
function Component(props: Props) { ... }.
•
Для children: React.ReactNode.
•
Для событий: React.ChangeEvent<HTMLInputElement>.
•
Не всегда нужен React.FC.
Когда использовать React.FC, а когда нет?
•
React.FC добавляет children по умолчанию.
•
Иногда это нежелательно.
•
Типизация defaultProps отличается.
•
Простые функции с Props обычно достаточно.
•
Выбирай единый стиль в проекте.
Как типизировать useState в React?
•
useState<number>(
•
фиксирует тип.
•
Для nullable: useState<User | null>(null).
•
Для complex объектов лучше интерфейс.
•
Ленивая инициализация: useState(() => compute()).
•
Избегай any в state.
Как типизировать useRef?
•
useRef<HTMLDivElement | null>(null).
•
Проверяй ref.current на null.
•
Для mutable значения: useRef<number>(0).
•
Не используй ref как state.
•
Для callbacks можно useCallback ref.
Что такое declaration merging и где оно встречается?
•
interface может объединяться по имени.
•
Удобно для расширения глобальных типов.
•
Часто используется для дополнения Window/NodeJS.ProcessEnv.
•
Может быть источником конфликтов.
•
Контролируй где объявляешь глобальные типы.
Как расширить тип Window или ProcessEnv?
•
Создай d.ts файл в проекте.
•
declare global { interface Window { ... } }.
•
Для env: declare namespace NodeJS { interface ProcessEnv { ... } }.
•
Не забудь export {} в файле.
•
Следи, чтобы include видел этот файл.
Что такое .d.ts файлы и зачем они нужны?
•
Это файлы деклараций типов.
•
Нужны для JS-библиотек без типов.
•
Могут описывать API без реализации.
•
Используются DefinitelyTyped (@types/*).
•
Подключаются через types/include.
Как добавить типы для JS-библиотеки без @types?
•
Сначала проверь, нет ли встроенных типов.
•
Если нет — создай minimal .d.ts с declare module 'lib'.
•
Постепенно уточняй типы по мере использования.
•
Можно написать wrapper API со строгими типами.
•
Для сложных случаев — генерация из OpenAPI/JSON schema.
Что такое moduleResolution и когда менять его?
•
Определяет как TS ищет модули.
•
NodeNext нужен для ESM/Node 16+.
•
Bundler подходит для Vite/webpack.
•
Classic почти не нужен.
•
Выбор зависит от рантайма и сборщика.
Как настроить алиасы путей (paths) в tsconfig?
•
Задай baseUrl.
•
Добавь paths: { '@/*': ['src/*'] }.
•
Настрой сборщик (webpack/vite) аналогично.
•
Настрой jest/vitest алиасы тоже.
•
Иначе в runtime алиасы не заработают.
Почему TS проходит, а в runtime модуль не находится?
•
TS проверяет пути по tsconfig paths.
•
Но Node/бандлер может не знать про алиасы.
•
Нужно настроить резолвер в сборщике/тестах.
•
Для Node можно использовать tsconfig-paths.
•
Всегда проверяй runtime конфигурацию.
Что такое isolatedModules и когда он нужен?
•
Требуется для transpile через Babel/'один файл'.
•
Запрещает некоторые конструкции (например, const enum).
•
Помогает совместимости со сборщиками.
•
В Next.js обычно включают.
•
Лучше держать включённым в фронтенд-проектах.
В чём разница между tsc и babel/swc при сборке TS?
•
tsc делает типовую проверку и может эмитить JS.
•
Babel/SWC быстро транспилируют, но не проверяют типы.
•
В таких схемах типчек запускают отдельно (tsc --noEmit).
•
Next/Vite часто используют SWC/Babel.
•
Проверка типов нужна в CI.
Как включить проверку типов без генерации JS?
•
Запусти: tsc --noEmit.
•
Или поставь noEmit: true в tsconfig.
•
Удобно для проектов, где сборку делает другой инструмент.
•
В CI делай отдельный шаг typecheck.
•
Ошибки типов тогда не попадут в прод.
Что такое source maps и как они помогают?
•
Связывают скомпилированный JS с исходным TS.
•
Упрощают отладку в браузере и Node.
•
Включается sourceMap: true.
•
В проде иногда отключают из-за размера и безопасности.
•
Для Sentry полезны.
Как правильно типизировать конфиг-объекты?
•
Используй const + as const для литералов.
•
Для проверки структуры применяй satisfies.
•
Избегай any.
•
Храни конфиг в одном месте, не размазывай.
•
Для env-значений делай явное преобразование типов.
Как типизировать process.env и убрать 'string | undefined'?
•
В runtime переменные могут отсутствовать.
•
Сначала валидируй наличие (например, через функцию requireEnv).
•
После проверки можно вернуть string.
•
Лучше делать единый слой конфигурации.
•
Для строгой схемы используй zod/valibot.
Как типизировать функцию, которая кидает ошибку (never)?
•
Функции, которые всегда кидают/завершают процесс, возвращают never.
•
Пример: function fail(msg: string): never { throw new Error(msg) }.
•
Удобно в exhaustive checks.
•
Помогает анализу потока.
•
Улучшает читабельность ошибок.
Что такое template literal types?
•
Типы строк с шаблоном: `user:${string}`.
•
Полезно для построения ключей и маршрутов.
•
Работают с union и mapped types.
•
Усложняют типы, используй аккуратно.
•
Отлично для событий/ID-шников.
Как типизировать строки формата UUID/id?
•
Полной валидации типами не сделать.
•
Можно сделать брендированный тип: type UUID = string & { __brand: 'UUID' }.
•
Преобразование только после проверки regex.
•
Это повышает безопасность API.
•
Без runtime проверки бренд бессмысленен.
Что такое branded types и зачем они нужны?
•
Это способ различать одинаковые примитивы (string vs Email).
•
Делается через пересечение с 'маркером'.
•
Требует фабрики/валидации.
•
Уменьшает ошибки при передаче параметров.
•
Полезно в доменной модели.
Как типизировать функции-валидаторы?
•
Возвращай boolean и type predicate.
•
Например: (x: unknown): x is User.
•
Держи проверки на одном уровне, без side effects.
•
Валидация схемой часто проще.
•
Добавь тесты на валидаторы.
Что такое conditional types?
•
Типы вида T extends U ? X : Y.
•
Используются для умных утилит.
•
Могут распределяться по union.
•
Иногда сильно замедляют компиляцию.
•
Применяй в основном для библиотечного кода.
Что такое infer в conditional types?
•
infer позволяет 'вытащить' часть типа.
•
Например, получить тип элемента массива.
•
Используется в ReturnType/Parameters.
•
Мощно, но сложнее читать.
•
Пиши примеры и тестируй типы.
Как получить тип элемента массива (array element type)?
•
Для массива T[] элемент — T.
•
Для произвольного: type Elem<A> = A extends (infer T)[] ? T : never.
•
Для readonly массивов учитывай readonly.
•
Полезно в обобщённых утилитах.
•
Не забывай про tuple.
Что такое utility types Required/Readonly и зачем?
•
Required делает поля обязательными.
•
Readonly делает поля только для чтения.
•
Используй для публичных интерфейсов и иммутабельности.
•
Есть ReadonlyArray и readonly tuple.
•
Уменьшает количество мутаций в коде.
Как типизировать partial update объекта безопаснее?
•
Не делай Partial<T> на всё подряд.
•
Ограничь набор полей: Partial<Pick<T, 'a' | 'b'>>.
•
Для запрета некоторых полей — Omit.
•
Валидируй данные перед применением.
•
Для API лучше отдельный DTO.
Как типизировать функцию merge без потери типов?
•
<A extends object, B extends object>(a: A, b: B): A & B.
•
Но учти конфликтующие ключи.
•
В runtime применяй Object.assign/spread.
•
Для глубокого merge типы сложнее.
•
Иногда лучше явное описание результата.
Как работать с readonly и мутациями объектов?
•
Readonly запрещает присваивание полям.
•
Для изменений создай копию через {...obj}.
•
Для массивов: [...arr].
•
Используй иммутабельные паттерны в state.
•
Для глубоких структур нужна дисциплина/immer.
Как типизировать объект, который может быть null?
•
Используй union: T | null.
•
Проверяй if (x == null) return.
•
Избегай ! для обхода.
•
Для chain доступа используй ?.
•
Продумай где именно допускается null.
Как правильно выбрать между null и undefined?
•
undefined чаще значит 'нет значения' по умолчанию.
•
null часто используется как явное 'пусто'.
•
Держи единый стиль в проекте.
•
В API лучше документировать.
•
В strictNullChecks оба требуют обработки.
Как типизировать функции с опциональными параметрами?
•
Параметр: foo(x?: string).
•
Или foo(x: string | undefined).
•
Учитывай, что x может быть undefined.
•
Задавай дефолт: function foo(x: string = 'a').
•
Не делай много опциональных подряд — лучше объект параметров.
Как типизировать 'options object' вместо длинного списка аргументов?
•
Сделай interface Options { ... }.
•
function f(opts: Options) {}.
•
Дай дефолты через деструктуризацию.
•
Это удобнее для расширения API.
•
Позволяет делать Partial<Options> для дефолтов.
Как работает structural typing в TypeScript?
•
В TS важна структура, а не имя типа.
•
Два типа совместимы, если поля совпадают.
•
Это удобно, но может скрыть ошибки в домене.
•
Branded types помогают различать.
•
Всегда думай о границах системы.
Что такое nominal typing и как имитировать его в TS?
•
Nominal — совместимость по имени типа.
•
В TS можно имитировать через бренды.
•
type UserId = string & { __brand: 'UserId' }.
•
Создай функцию-конструктор после валидации.
•
Это снижает случайные подстановки.
Как типизировать функции работы с массивами (map/filter/reduce) без any?
•
TS выводит типы колбэков автоматически.
•
Следи, чтобы исходный массив был типизирован.
•
Для reduce указывай initial value и тип аккумулятора.
•
Избегай reduce без initial — могут быть проблемы.
•
Для filter иногда нужен type guard.
Как сделать type guard для filter?
•
Пример: const isDefined = <T>(x: T | undefined): x is T => x !== undefined.
•
Тогда arr.filter(isDefined) уберёт undefined.
•
Аналогично для null.
•
Удобно в пайплайнах данных.
•
Делай такие утилиты в одном месте.
Что такое satisfies для массивов и словарей?
•
Можно проверить тип массива не теряя literal types.
•
Пример: const routes = [...] satisfies Route[].
•
Компилятор проверит структуру элементов.
•
Но сохранит конкретику значений.
•
Хороший баланс между 'как есть' и строгой проверкой.
Как ускорить компиляцию TypeScript в большом проекте?
•
Включи incremental.
•
Используй project references.
•
Уменьши include и исключи build/output папки.
•
Избегай сложных conditional types в горячих местах.
•
Обнови TS до актуальной версии.
Что такое project references и зачем они нужны?
•
Это разбиение монорепо на проекты TS.
•
Ускоряет сборку и typecheck.
•
Позволяет 'инкрементально' проверять только изменённые части.
•
Требует composite: true.
•
Хорошо для больших кодовых баз.
Как настроить monorepo с TypeScript?
•
Используй workspace менеджер (pnpm/yarn/npm).
•
Сделай base tsconfig и наследуйся.
•
Включи project references.
•
Следи за едиными версиями TS и типов.
•
Настрой линтер и форматтер одинаково.
Как правильно типизировать публичный API библиотеки?
•
Экспортируй только нужные типы.
•
Не экспортируй внутренние детали.
•
Стабилизируй contract и версионируй.
•
Генерируй d.ts (declaration: true).
•
Тестируй типы через dtslint или tsd.
Как проверить типы в CI?
•
Добавь скрипт: npm run typecheck.
•
Запускай tsc --noEmit.
•
Отдельно запускай eslint/test.
•
Не полагайся на IDE.
•
Сделай проверку обязательной перед merge.
Как типизировать Node.js проект на TypeScript?
•
Настрой module и moduleResolution под ESM/CJS.
•
Добавь @types/node.
•
Выбери раннер: ts-node, tsx или сборку через tsc.
•
Следи за пути/алиасами.
•
Проверь запуск в проде (без ts-node).
В чём разница между ESM и CommonJS в контексте TypeScript?
•
ESM использует import/export в runtime.
•
CJS использует require/module.exports.
•
TS может эмитить оба варианта.
•
В Node важны package.json type и расширения .mts/.cts.
•
Ошибки чаще из-за смешивания систем.
Как настроить TypeScript для Node ESM (NodeNext)?
•
module: NodeNext и moduleResolution: NodeNext.
•
В package.json поставь type: module.
•
Используй расширения/exports правильно.
•
Для типов можно .d.ts или .mts.
•
Проверяй сборку и запуск вместе.
Как типизировать Express middleware?
•
Установи @types/express.
•
Типы Request, Response, NextFunction.
•
Расширяй Request через declaration merging, если добавляешь поля.
•
Делай явные типы для body/query/params.
•
Валидируй входные данные.
Как типизировать DTO и валидацию входных данных?
•
Типы TS не валидируют runtime.
•
Используй zod/yup/class-validator.
•
Схема должна быть источником истины.
•
Генерируй тип из схемы, если библиотека позволяет.
•
Держи валидатор на границе системы (API).
Как безопасно работать с внешними данными: JSON, API, localStorage?
•
Считай всё внешнее как unknown.
•
Валидируй структуру (schema/type guards).
•
Обрабатывай отсутствие полей и версии.
•
Логируй ошибки парсинга и фолбэки.
•
Не делай as без проверок.
Как типизировать localStorage и преобразование типов?
•
localStorage хранит строки.
•
Делай функции getJSON<T>() с unknown + валидатор.
•
Для чисел/булевых — явное преобразование.
•
Обрабатывай отсутствие ключа.
•
Версионируй формат хранения.
Как правильно типизировать ошибки для доменной логики?
•
Делай свои классы ошибок (extends Error).
•
Добавляй код/тип причины.
•
Лови и маппь в верхнем слое (API/UI).
•
Не кидай строками.
•
Документируй какие ошибки возможны.
Какие типичные анти-паттерны в TypeScript стоит избегать?
•
any и цепочки as as.
•
! вместо проверок.
•
Сложные типы ради типов без выгоды.
•
Дублирование DTO вместо утилит Pick/Omit.
•
'Магия' в типах без тестов и примеров.
Как писать поддерживаемые типы: практические правила?
•
Сначала простые типы, усложняй по мере нужды.
•
На границах системы валидируй runtime.
•
Не скрывай проблемы через any/as.
•
Используй discriminated unions для состояний.
•
Поддерживай единый стиль и типчек в CI.
TypeScript — Программирование — Технологии — FAQ Портал