Инструменты и компилятор
Компиляция TypeScript в JavaScript через tsc, настройка tsconfig.json и опции компилятора строгого режима.
11 вопросов
JuniorТеорияОчень частоКак скомпилировать TypeScript в JavaScript?
Как скомпилировать TypeScript в JavaScript?
Компилятор TypeScript tsc транспилирует файлы .ts в .js. Его настраивают через tsconfig.json, где compilerOptions задают target, module, outDir и strict. Запуск tsc сообщает об ошибках типов на этапе компиляции и выдаёт JavaScript с полностью стёртыми типами.
Типичные ошибки
- ✗Думать, что типы остаются в выводе —
tscстирает их, в JavaScript типов нет - ✗Считать, что браузеры запускают
.tsнапрямую без шага компиляции - ✗Забывать, что именно
tsconfig.jsonуправляет поведениемtsc
Уточняющие вопросы
- →Что контролирует опция
targetвtsconfig.json? - →Выполняет ли
tscоптимизации или только проверяет типы и выдаёт код?
MiddleТеорияОчень частоЧто делает включение строгого режима strict в tsconfig?
Что делает включение строгого режима strict в tsconfig?
Установка "strict": true в tsconfig.json разом включает семейство строгих флагов проверки типов, включая strictNullChecks (чтобы null и undefined нельзя было молча присвоить другим типам) и noImplicitAny (ошибка на любой выведенный any). Это максимизирует типобезопасность и рекомендуется для новых проектов.
Типичные ошибки
- ✗Думать, что
strict— одна проверка, а не зонтик над несколькими флагами - ✗Считать, что он добавляет проверки на null во время выполнения — все проверки только на этапе компиляции
- ✗Путать
noImplicitAnyс полным запретомany(явныйanyдопустим)
Уточняющие вопросы
- →Что именно
strictNullChecksменяет в присваиваемости? - →Можно ли включить отдельные строгие флаги, не включая весь
strict?
JuniorТеорияЧастоЧто контролирует опция target в JavaScript, который выдаёт tsc?
Что контролирует опция target в JavaScript, который выдаёт tsc?
target выбирает версию ECMAScript, которую выдаёт tsc. Синтаксис новее целевой версии переписывается в эквивалентный более старый; синтаксис, который цель уже понимает, выдаётся как есть. Опция также выбирает набор lib по умолчанию, но никогда не добавляет полифилы для отсутствующего рантайм-API.
Типичные ошибки
- ✗Путать
target(уровень синтаксиса) сmodule(формат модулей на выходе) - ✗Ждать от
targetполифилов — она переписывает синтаксис, а не рантайм-API - ✗Забывать, что
targetзаодно выбирает наборlibпо умолчанию
Уточняющие вопросы
- →Почему при низком
targetвы всё равно можете вызыватьPromise, хотя полифил не выдаётся? - →Как через
libпереопределить декларации, которыеtargetвыбрал по умолчанию?
JuniorТеорияЧастоЗачем включать sourceMap и что при этом выдаёт компилятор?
Зачем включать sourceMap и что при этом выдаёт компилятор?
sourceMap: true заставляет tsc выдавать .js.map рядом с каждым .js, сопоставляя каждую позицию в выводе с исходной строкой и колонкой .ts. Отладчик и стек-трейсы тогда указывают на ваш исходник TypeScript, а не на скомпилированный вывод. Карта — отдельный артефакт сборки и ничего не меняет во время выполнения.
Типичные ошибки
- ✗Думать, что карта меняет поведение выданного JavaScript — это отдельный артефакт
- ✗Считать, что карта хранит типы, а не сопоставление позиций
- ✗Полагать, что браузер перекомпилирует
.ts, а не просто сопоставляет позиции
Уточняющие вопросы
- →Что даёт
inlineSourcesповерх обычной карты исходников? - →Почему команды избегают поставлять
.js.mapвместе с публичным продакшен-бандлом?
MiddleТеорияЧастоЧто выдаёт declaration: true и зачем это обязательно публикуемой библиотеке?
Что выдаёт declaration: true и зачем это обязательно публикуемой библиотеке?
declaration: true заставляет tsc писать .d.ts рядом с каждым выданным .js, где лежат публичные сигнатуры типов, а все тела реализаций вырезаны. Пакет поставляет только JavaScript, поэтому без этих файлов потребитель видит any; поле types в package.json указывает на входной .d.ts.
Типичные ошибки
- ✗Думать, что
.d.tsнесёт код реализации, а не одни лишь вырезанные сигнатуры - ✗Считать, что потребитель может проверить типы пакета по одному только выданному
.js - ✗Забывать, что
package.jsonдолжен указывать на входной.d.tsчерез полеtypes
Уточняющие вопросы
- →Что ломается, когда экспортированная сигнатура ссылается на неэкспортированный тип?
- →Как
declarationMapулучшает переход к определению для потребителя пакета?
MiddleТеорияЧастоЧто делает ключевое слово declare и что такое файл .d.ts?
Что делает ключевое слово declare и что такое файл .d.ts?
declare вводит ambient-объявление — оно сообщает компилятору о значении, типе, функции или модуле, который существует в другом месте (глобал, библиотека на чистом JS, переменная из подключённого скрипта), не давая реализации. Оно только для типов и не эмитит JavaScript. Файлы объявлений (.d.ts) собирают такие ambient-объявления, описывая форму кода, который компилятор не видит, например нетипизированные библиотеки.
Типичные ошибки
- ✗Думать, что
declareэмитит или выполняет код — он только для типов, без вывода JavaScript - ✗Считать, что
.d.ts-файл содержит реализации, а не сигнатуры типов - ✗Полагать, что
declareперепроверяет значение в рантайме, а не только при компиляции
Уточняющие вопросы
- →Как добавить типы для библиотеки на чистом JavaScript, которая их не поставляет?
- →Когда использовать
declare global, а когда объявление модуля?
MiddleТеорияЧастоКак noImplicitAny соотносится с зонтичным флагом strict?
Как noImplicitAny соотносится с зонтичным флагом strict?
noImplicitAny — один член семейства строгих флагов: он даёт ошибку там, где компилятор молча откатывается к any, например на параметре без аннотации. strict: true включает всё семейство разом, а явно заданный член перекрывает зонтик.
Типичные ошибки
- ✗Считать
strictиnoImplicitAnyнезависимыми флагами, а не зонтиком и его членом - ✗Думать, что
strict: trueжёстко включает члены и их нельзя ослабить по одному - ✗Путать
noImplicitAnyс запретом писатьanyявно
Уточняющие вопросы
- →Какие ещё проверки включает семейство строгих флагов, кроме
noImplicitAny? - →Где неявный
anyвсё же проскакивает даже при включённомnoImplicitAny?
MiddleТеорияЧастоПочему большинство проектов включают skipLibCheck и чем за это платят?
Почему большинство проектов включают skipLibCheck и чем за это платят?
skipLibCheck: true не даёт tsc проверять по типам содержимое файлов .d.ts — как ваших, так и всего в node_modules. Это сокращает время сборки и глушит ошибки из чужих деклараций, которые вы не исправите. Взамен настоящая ошибка внутри декларации остаётся незамеченной; ваш исходник .ts проверяется как прежде.
Типичные ошибки
- ✗Думать, что он вовсе отбрасывает типы библиотек — места вызова по-прежнему проверяются по ним
- ✗Считать, что он трогает лишь
node_modules, а не ваши собственные выданные.d.ts - ✗Полагать, что он бесплатен — настоящая ошибка внутри файла деклараций заглушается
Уточняющие вопросы
- →Как
skipLibCheckскрывает конфликт между двумя копиями типов одной библиотеки? - →Когда его стоит выключить и что обычно ломается сразу после этого?
MiddleТеорияЧастоКакой класс ошибок устраняет strictNullChecks и по какому правилу?
Какой класс ошибок устраняет strictNullChecks и по какому правилу?
Без него null и undefined присваиваются любому типу, поэтому string может незаметно хранить одно из них, а разыменование падает во время выполнения. Включение убирает оба из всех остальных типов: они должны стоять в явном union вроде string | null, что вынуждает сузить тип.
Типичные ошибки
- ✗Думать, что он добавляет проверки на null во время выполнения — проверка только при компиляции
- ✗Забывать, что он охватывает и
undefined, а не толькоnull - ✗Ждать, что он вовсе запретит
null, вместо требования явного union
Уточняющие вопросы
- →Как сузить
string | null, чтобы компилятор допустил обращение к полю? - →Что делает с этой проверкой оператор
!и почему это рискованно?
MiddleТеорияИногдаКакую ошибку ловит noUncheckedIndexedAccess и что именно он меняет?
Какую ошибку ловит noUncheckedIndexedAccess и что именно он меняет?
Обращение по индексу к массиву или типу с index-сигнатурой может промахнуться, но по умолчанию arr[i] имеет тип просто T и сразу разыменовывается. Флаг добавляет undefined к каждому такому обращению, тип становится T | undefined, и сначала нужна проверка. Он подключается вручную и не входит в strict.
Типичные ошибки
- ✗Считать, что
strictуже включает его — это отдельный флаг, включаемый вручную - ✗Думать, что он добавляет проверку границ в рантайме, а не расширяет статический тип
- ✗Забывать, что он действует и на обычный доступ к элементу массива, а не только на index-сигнатуры
Уточняющие вопросы
- →Почему этот флаг намеренно оставлен вне семейства
strict? - →Как деструктуризация и цикл
for...ofобходят добавленныйundefined?
SeniorТеорияИногдаКак добавить рукописные .d.ts к JavaScript-пакету, который их не поставляет?
Как добавить рукописные .d.ts к JavaScript-пакету, который их не поставляет?
Декларации пишут вручную и либо кладут внутрь пакета, указав на них полем types в package.json, либо публикуют отдельно как @types/<name>, который компилятор находит сам. Рукописный .d.ts никто не сверяет с настоящим JavaScript, поэтому расхождение с рантаймом незаметно.
Типичные ошибки
- ✗Думать, что
tscсверяет рукописный.d.tsс настоящим JavaScript пакета - ✗Считать, что JavaScript-пакет надо сперва переписать на TypeScript, чтобы его типизировать
- ✗Забывать поле
types, когда декларации лежат внутри самого пакета
Уточняющие вопросы
- →Как компилятор выбирает между
.d.tsвнутри пакета и пакетом@types/<name>? - →Что удерживает рукописную декларацию в синхроне, пока JavaScript-пакет выпускает обновления?