Здесь показаны различия между двумя версиями данной страницы.
| Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
|
typescript:tsconfig.json [2022/11/14 14:12] werwolf |
typescript:tsconfig.json [2023/01/12 12:18] (текущий) |
||
|---|---|---|---|
| Строка 1: | Строка 1: | ||
| + | ===== Структура tsconfig ===== | ||
| + | |||
| + | Рассмотрим структуру и некоторые особенности конфига. | ||
| + | |||
| + | * ''tsconfig.json'' состоит из двух частей. Какие-то опции необходимо указывать в ''root'', а какие-то в ''compilerOptions'' | ||
| + | * ''tsconfig.json'' поддерживает комментарии. Такие IDE как WebStorm и Visual Studio Code знают об этом и не выделяют комментарии как синтаксическую ошибку | ||
| + | * ''tsconfig.json'' поддерживает наследование. Опции можно разделить по некоторому принципу, описать их в разных файлах и объединить с помощью специальной директивы | ||
| + | |||
| + | Это болванка нашего ''tsconfig.json'': | ||
| + | |||
| + | <code javascript> | ||
| + | { | ||
| + | // extends позволяет обогатить опции другими опциями из указанного файла | ||
| + | // файлом tsconfig-checks.json займёмся во второй части статьи | ||
| + | "extends": "./tsconfig-checks.json", | ||
| + | // в корне конфига находятся project-specific опции | ||
| + | "compilerOptions": { | ||
| + | // здесь все настройки, связанные с компилятором | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | К ''root'' опциям относится только следующие: ''extends'', ''files'', ''include'', ''exclude'', ''references'', ''typeAcquisition''. Из них мы будем рассматривать первые 4. Все остальные опции размещаются в ''compilerOptions''. | ||
| + | |||
| + | Иногда в ''root'' секции конфига можно встретить такие опции как ''compileOnSave'' и ''ts-node''. Эти опции не являются официальными и используются IDE для своих целей. | ||
| + | |||
| + | ===== Секция root ===== | ||
| + | |||
| + | ==== extends ==== | ||
| + | |||
| + | **Type: string | false, default: false.** | ||
| + | |||
| + | Указывает путь к файлу из которого нужно унаследовать опции. По большей части, служит инструментом упорядочивания. Можно разделить опции по некой логике, чтобы они не смешивались. Например, вынести настройки строгости в отдельный файл, как в примере болванки конфига. Однако, учитывая поддержку комментариев в ''tsconfig.json'' это можно сделать проще: | ||
| + | |||
| + | <code javascript> | ||
| + | { | ||
| + | "compilerOptions": { | ||
| + | // блок базовых настроек | ||
| + | |||
| + | // блок настроек строгости | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Рассмотрим другой use-case, где комментариями отделаться не получится. Если необходимо создать production и development конфиги. Так бы мог выглядеть ''tsconfig-dev.json'' версия конфига: | ||
| + | |||
| + | <code javascript> | ||
| + | { | ||
| + | "extends": "./tsconfig.json", | ||
| + | "compilerOptions": { | ||
| + | // переопределяем настройки, которые нужны только для dev режима | ||
| + | "sourceMap": true, | ||
| + | "watch": true | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | В целом, я рекомендую пользоваться ''extends''. Однако, сильно дробить настройки не рекомендую. Это может привести к запутыванию. В том числе по причине того, что множественное наследование не поддерживается. | ||
| + | |||
| + | Если вы решите использовать эту опцию. То увидеть итоговую, объединённую версию конфига поможет команда ''tsc --showConfig''. | ||
| + | |||
| + | ==== files ==== | ||
| + | |||
| + | **Type: string[] | false, default: false, связана с** ''include''**.** | ||
| + | |||
| + | Указать список конкретных файлов для компиляции можно использовав данную опцию. | ||
| + | |||
| + | <code javascript> | ||
| + | { | ||
| + | "compilerOptions": {}, | ||
| + | "files": [ | ||
| + | "core.ts", | ||
| + | "app.ts" | ||
| + | ] | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Данная опция подходит лишь для совсем маленьких проектов из нескольких файлов. | ||
| + | |||
| + | ==== include ==== | ||
| + | |||
| + | **Type string[], default: зависит от значения** ''files''**, связана с** ''exclude''**.** | ||
| + | |||
| + | Если опция ''files'' не указана, то TypeScript будет использовать эту директиву для поиска компилируемых файлов. Если ''include'' так же не указана, то её значение будет неявно объявлено как ''["%%**/*%%"]''. Это означает, что поиск файлов будет осуществляться во всех папках и их подпапках. Такое поведение не оптимально, поэтому в целях производительности лучше всегда указывать конкретные пути. Можно прописывать как пути к конкретным файлам, так и паттерны путей. | ||
| + | |||
| + | <code javascript> | ||
| + | { | ||
| + | "compilerOptions": {}, | ||
| + | "include": [ | ||
| + | "src/**/*", | ||
| + | "tests/**/*" | ||
| + | ] | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Если паттерны не указывают конкретных расширений, то TypeScript будет искать файлы с расширениями ''.ts'', ''.tsx'' и ''.d.ts''. А если включен флаг ''allowJs'', то ещё ''.js'' и ''.jsx''. | ||
| + | |||
| + | Следующие форматы записей делают одно и тоже ''src'', ''./src'', ''src%%/**/*%%''. Я предпочитаю вариант ''./src''. | ||
| + | |||
| + | Технически, используя опции ''include'' и ''exclude'', TypeScript сгенерирует список всех подходящих файлов и поместит их в ''files''. Это можно наблюдать если выполнить команду ''tsc --showConfig''. | ||
| + | |||
| + | ==== exclude ==== | ||
| + | |||
| + | **Type: string[], default: ["node_modules", "bower_components", "jspm_packages"].** | ||
| + | |||
| + | Директива служит для того, чтобы исключать некоторые лишние пути или файлы, которые включились директивой ''include''. По умолчанию, опция имеет значение путей пакетных менеджеров ''npm'', ''bower'' и ''jspm'', так как модули в них уже собраны. Помимо этого, TypeScript будет так же игнорировать папку из опции ''outDir'', если она указана. Это папка, куда помещаются собранные артефакты сборки. Логично, что их нужно исключить. Если добавить свои значения в эту опцию, то необходимо не забыть восстановить умолчания. Так как пользовательские значения не объединяются со значениями по умолчанию. Другими словами, необходимо вручную указать корень модулей своего пакетного менеджера. | ||
| + | |||
| + | <code javascript> | ||
| + | { | ||
| + | "compilerOptions": {}, | ||
| + | "exclude": [ | ||
| + | "node_modules", | ||
| + | "./src/**/*.spec.ts" | ||
| + | ] | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Опция ''exclude'' не может исключить файлы, указанные через ''files''. | ||
| + | |||
| + | Опция ''exclude'' не может исключить файлы, если они импортируются в других файлах, которые не исключены. | ||
| + | |||
| + | ===== Секция compilerOptions ===== | ||
| + | |||
| + | ==== target ==== | ||
| + | |||
| + | **Type: string, default:** ''ES3''**, влияет на опции** ''lib''**,** ''module''**.** | ||
| + | |||
| + | Версия стандарта ECMAScript, в которую будет скомпилирован код. Здесь большой выбор: ''ES3'', ''ES5'', ''ES6'' (он же ''ES2015''), ''ES2016'', ''ES2017'', ''ES2018'', ''ES2019'', ''ES2020'', ''ESNext''. Для backend приложений/пакетов подойдёт ''ES6'', если рассчитываете только на современные версии ''Node.js'' и ''ES5'', если хотите поддержать более старые версии. На данный момент стандарт ''ES6'', с небольшими оговорками, поддерживается [[https://caniuse.com/es6|97.29% браузеров]]. Так что для frontend приложений ситуация аналогичная. | ||
| + | |||
| + | ==== module ==== | ||
| + | |||
| + | **Type: string, default: зависит от** ''target''**, влияет на опцию** ''moduleResolution''**.** | ||
| + | |||
| + | Модульная система, которую будет использовать ваше собранное приложение. На выбор: ''None'', ''CommonJS'', ''AMD'', ''System'', ''UMD'', ''ES6'', ''ES2015'', ''ES2020'' или ''ESNext''. Для backend приложений/пакетов подойдёт ''ES6'' или ''CommonJS'' в зависимости от версий ''Node.js'', которые хотите поддерживать. Для frontend приложений под современные браузеры также подходит ''ES6''. А для поддержки более старых браузеров и для изоморфных приложений, определённо стоит выбрать ''UMD''. | ||
| + | |||
| + | Если ваша ситуация не такая простая или хотите знать все тонкости модульных систем, тогда придётся всё-таки изучить [[https://www.typescriptlang.org/docs/handbook/modules.html|подробную документацию]]. | ||
| + | |||
| + | ==== moduleResolution ==== | ||
| + | |||
| + | **Type: string, default: зависит от** ''module''**.** | ||
| + | |||
| + | Стратегия, которая будет использоваться для импорта модулей. Здесь всего две опции: ''node'' и ''classic''. При этом ''classic'' в 99% не будет использоваться, так как это legacy. Однако, я специально упомянул этот флаг, так как он меняется в зависимости от предыдущего флага. При изменении значения ''module'' режим ''moduleResolution'' может переключиться на ''classic'' и в консоли начнут появляться сообщения об ошибках на строчках с импортами. | ||
| + | |||
| + | Во избежание описанной ситуации, я рекомендую всегда явно указывать значение ''node'' для данного флага. | ||
| + | |||
| + | ==== lib ==== | ||
| + | |||
| + | **Type: string[], default: зависит от** ''target''**.** | ||
| + | |||
| + | В зависимости от того какой ''target'' установлен в конфиге, TypeScript подключает тайпинги (''*.d.ts-файлы'') для поддержки соответствующих спецификаций. Например, если ваш ''target'' установлен в ''ES6'', то TypeScript подключит поддержку ''array.find'' и прочих вещей, которые есть в стандарте. Но если ''target'' стоит ''ES5'', то использовать метод массива ''find'' нельзя, так как его не существует в этой версии JavaScript. Можно подключить полифилы. Однако, для того, чтобы TypeScript понял, что теперь данную функциональность можно использовать, необходимо подключить необходимые тайпинги в секции ''lib''. При этом, можно подключить как весь стандарт ''ES2015'', так и его часть ''ES2015.Core'' (только методы ''find'', ''findIndex'' и т. д.). | ||
| + | |||
| + | Конечно, правильным выбором будет подключать тайпинги только той функциональности, для которой установлены полифилы. | ||
| + | |||
| + | <code javascript> | ||
| + | Для --target ES5 подключаются: DOM, ES5, ScriptHost | ||
| + | Для --target ES6: DOM, ES6, DOM.Iterable, ScriptHost | ||
| + | </code> | ||
| + | |||
| + | Как только вы что-либо добавляете в ''lib'' умолчания сбрасываются. Необходимо руками добавить то, что нужно, например ''DOM'': | ||
| + | |||
| + | <code javascript> | ||
| + | { | ||
| + | "compilerOptions": { | ||
| + | "target": "ES5", | ||
| + | "lib": [ | ||
| + | "DOM", | ||
| + | "ES2015.Core" | ||
| + | ] | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== outDir ==== | ||
| + | |||
| + | **Type: string, default: равняется корневой директории.** | ||
| + | |||
| + | Конечная папка, куда будут помещаться собранные артефакты. К ним относятся: ''.js'', ''.d.ts'', и ''.js.map'' файлы. Если не указывать значение для данной опции, то все вышеуказанные файлы будут повторять структуру исходных файлов в корне вашего проекта. В таком случае будет сложно удалять предыдущие билды и описывать ''.gitignore'' файлы. Да и кодовая база будет похожа на свалку. Советую складывать все артефакты в одну папку, которую легко удалить или заигнорировать системой контроля версий. | ||
| + | |||
| + | Если оставить опцию ''outDir'' пустой: | ||
| + | |||
| + | <code> | ||
| + | ├── module | ||
| + | │ └── core.js | ||
| + | │ └── core.ts | ||
| + | ├── index.js | ||
| + | └── index.ts | ||
| + | </code> | ||
| + | |||
| + | Если указать ''outDir'': | ||
| + | |||
| + | <code> | ||
| + | ├── dist | ||
| + | │ └── module | ||
| + | │ | └── core.js | ||
| + | │ └── index.js | ||
| + | ├── module | ||
| + | │ └── core.ts | ||
| + | └── index.ts | ||
| + | </code> | ||
| + | |||
| + | ==== outFile ==== | ||
| + | |||
| + | **Type: string, default: none.** | ||
| + | |||
| + | Судя по описанию, данная опция позволяет объединить все файлы в один. Кажется, что бандлеры вроде ''webpack'' больше не нужны… Однако, опция работает только если значение ''module'' указано ''None'', ''System'' или ''AMD''. К огромному сожалению, опция не будет работать с модулями ''CommonJS'' или ''ES6''. Поэтому скорее всего использовать ''outFile'' не придётся. Так как опция выглядит максимально привлекательно, но работает не так как ожидается, я решил предупредить вас об этом гигантском подводном камне. | ||
| + | |||
| + | ==== allowSyntheticDefaultImports ==== | ||
| + | |||
| + | **Type: boolean, default: зависит от** ''module'' **или** ''esModuleInterop''**.** | ||
| + | |||
| + | Если какая-либо библиотека не имеет ''default import'', лоадеры вроде ''ts-loader'' или ''babel-loader'' автоматически создают их. Однако, ''d.ts-файлы'' библиотеки об этом не знают. Данный флаг говорит компилятору, что можно писать следующим образом: | ||
| + | |||
| + | <code javascript> | ||
| + | // вместо такого импорта | ||
| + | import * as React from 'react'; | ||
| + | // можно писать такой | ||
| + | import React from 'react'; | ||
| + | </code> | ||
| + | |||
| + | Опция включена по умолчанию, если включен флаг ''esModuleInterop'' или ''module'' %%===%% "system". | ||
| + | |||
| + | ==== esModuleInterop ==== | ||
| + | |||
| + | **Type: boolean, default: false.** | ||
| + | |||
| + | За счёт добавления болерплейта в выходной код, позволяет импортировать ''CommonJS'' пакеты как ''ES6''. | ||
| + | |||
| + | <code javascript> | ||
| + | // библиотека moment экспортируется только как CommonJS | ||
| + | // пытаемся импортировать её как ES6 | ||
| + | import Moment from 'moment'; | ||
| + | |||
| + | // без флага esModuleInterop результат undefined | ||
| + | console.log(Moment); | ||
| + | |||
| + | // c флагом результат [object Object] | ||
| + | console.log(Moment); | ||
| + | </code> | ||
| + | |||
| + | Данный флаг по зависимости активирует ''allowSyntheticDefaultImports''. Вместе они помогают избавиться от зоопарка разных импортов и писать их единообразно по всему проекту. | ||
| + | |||
| + | ==== alwaysStrict ==== | ||
| + | |||
| + | **Type: boolean, default: зависит от** ''strict''**.** | ||
| + | |||
| + | Компилятор будет парсить код в ''strict mode'' и добавлять ''“use strict”'' в выходные файлы. | ||
| + | |||
| + | По умолчанию false, но если включен флаг ''strict'', то true. | ||
| + | |||
| + | ==== downlevelIteration ==== | ||
| + | |||
| + | **Type: boolean, default: false.** | ||
| + | |||
| + | Спецификация ''ES6'' добавила новый синтаксис для итерирования: цикл ''for / of'', ''array spread'', ''arguments spread''. Если код проекта преобразовывается в ''ES5'', то конструкция с циклом ''for / of'' будет преобразована в обычный ''for'': | ||
| + | |||
| + | <code javascript> | ||
| + | // код es6 | ||
| + | const str = 'Hello!'; | ||
| + | for (const s of str) { | ||
| + | console.log(s); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | <code javascript> | ||
| + | // код es5 без downlevelIteration | ||
| + | var str = "Hello!"; | ||
| + | for (var _i = 0, str_1 = str; _i < str_1.length; _i++) { | ||
| + | var s = str_1[_i]; | ||
| + | console.log(s); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Однако, некоторые символы, такие как ''emoji'' кодируются с помощью двух символов. Т. е. такое преобразование в некоторых местах будет работать не так, как ожидается. Включенный флаг ''downlevelIteration'' генерирует более многословный и более "правильный", но менее производительный код. Код получается действительно очень большим, поэтому не буду занимать место на экране. Если интересно посмотреть пример, то перейдите в [[https://www.typescriptlang.org/play?#code/MYewdgzgLgBNBOMC8MBEAJApgG2yAhKgNwBQAZiIgBSiSwQwhlxTwCUMA3iTDLRCGyYAdHgDmVCG1IBfIA|playground]] и выберете в настройках ''target -> es5'', ''downlevelIteration -> true''. | ||
| + | |||
| + | Для работы данного флага, необходимо, чтобы в браузере была реализация ''Symbol.iterator''. В противном случае необходимо установить полифил. | ||
| + | |||
| + | ==== forceConsistentCasingInFileNames ==== | ||
| + | |||
| + | **Type: boolean, default: false.** | ||
| + | |||
| + | Включает режим чувствительности к регистру (case-sensitive) для импорта файлов. Таким образом, даже в case-insensitive файловых системах при попытке сделать импорт ''import FileManager from './FileManager.ts''', если файл в действительности называется ''fileManager.ts'', приведёт к ошибке. Перестраховаться лишний раз не повредит. TypeScript - это про строгость. | ||
| + | |||
| + | ===== Опции секции compilerOptions, которые нужны не в каждом проекте ===== | ||
| + | |||
| + | ==== declaration ==== | ||
| + | |||
| + | **Type: boolean, default: false.** | ||
| + | |||
| + | С помощью включения данного флага, помимо JavaScript файлов, к ним будут генерироваться файлы-аннотации, известные как ''d.ts''-файлы или тайпинги. Благодаря тайпингам становится возможным определение типов для уже скомпилированных js файлов. Другими словами код попадает в ''js'', а типы в ''d.ts''-файлы. Это полезно в случае, например, если вы публикуете свой пакет в ''npm''. Такой библиотекой смогут пользоваться разработчики, которые пишут как на чистом JavaScript, так и на TypeScript. | ||
| + | |||
| + | ==== declarationDir ==== | ||
| + | |||
| + | **Type: string, default: none, связан с** ''declaration''**.** | ||
| + | |||
| + | По умолчанию тайпинги генерируются рядом с ''js''-файлами. Используя данную опцию можно перенаправить все ''d.ts''-файлы в отдельную папку. | ||
| + | |||
| + | ==== emitDeclarationOnly ==== | ||
| + | |||
| + | **Type: boolean, default: false, связан с** ''declaration''**.** | ||
| + | |||
| + | Если по какой-то причине вам нужны только ''d.ts''-файлы, то включение данного флага предотвратит генерацию ''js''-файлов. | ||
| + | |||
| + | ==== allowJs ==== | ||
| + | |||
| + | **Type: boolean, default: false.** | ||
| + | |||
| + | Портировать ваш JavaScript проект на TypeScript поможет данный флаг. Активировав ''allowJs'' TypeScript компилятор будет обрабатывать не только ''ts'' файлы, но и ''js''. Нет нужды полностью мигрировать проект, прежде чем продолжить его разработку. Можно это делать файл за файлом, просто меняя расширение и добавляя типизацию. А новый функционал сразу можно писать на TypeScript. | ||
| + | |||
| + | ==== checkJs ==== | ||
| + | |||
| + | **Type: boolean, default: false, связан с** ''allowJs''**.** | ||
| + | |||
| + | TypeScript будет проверять ошибки не только в ''ts'', но и в ''js''-файлах. Помимо встроенных тайпингов для языковых конструкций JavaScript, TS-компилятор так же умеет использовать jsDoc для анализа файлов. Я предпочитаю не использовать этот флаг, а наводить порядок в коде в момент его типизации. Однако, если в вашем проекте хорошее покрытие кода jsDoc, стоит попробовать. | ||
| + | |||
| + | С версии 4.1 при включении ''checkJs'', флаг ''allowJs'' включается автоматически. | ||
| + | |||
| + | ==== experimentalDecorators и emitDecoratorMetadata ==== | ||
| + | |||
| + | **Type: boolean, default: false.** | ||
| + | |||
| + | ''Декоратор'' - это стандартный паттерн из мира ООП и его можно реализовывать классическим образом, создавая классы или функции-обёртки. Однако, с помощью двух вышеперечисленных флагов можно включить экспериментальный синтаксис декораторов. Данный синтаксис позволяет декорировать классы, их методы и свойства, модификаторы доступа, а так же аргументы функций используя простой и распространённый во многих языках программирования [[https://refactoring.guru/ru/design-patterns/decorator|синтаксис]] ''@''. | ||
| + | |||
| + | Флаг ''experimentalDecorators'' просто активирует синтаксис, а ''emitDecoratorMetadata'' в рантайме предоставляет декораторам дополнительные мета-данные, с помощью которых можно значительно расширить области применения данной фичи. | ||
| + | |||
| + | Для работы ''emitDecoratorMetadata'' необходимо подтянуть в проект библиотеку [[https://github.com/rbuckton/reflect-metadata|reflect-metadata]]. | ||
| + | |||
| + | ==== resolveJsonModule ==== | ||
| + | |||
| + | **Type: boolean, default: false.** | ||
| + | |||
| + | Флаг позволяет включить возможность импортировать ''*.json'' файлы. Ничего дополнительно устанавливать не требуется. | ||
| + | |||
| + | <code javascript> | ||
| + | // необходимо указывать расширение .json | ||
| + | import config from './config.json' | ||
| + | </code> | ||
| + | |||
| + | ==== jsx ==== | ||
| + | |||
| + | **Type: string, default: none.** | ||
| + | |||
| + | Если проект использует React, необходимо включить поддержку ''jsx''. В подавляющем большинстве случаев будет достаточно опций ''react'' или ''react-native''. Так же есть возможность оставить ''jsx-код'' нетронутым с помощью опции ''preserve'' или использовать кастомные преобразователи ''react-jsx'' и ''react-jsxdev''. | ||
| + | |||
| + | ===== Завершение первой части ===== | ||
| + | |||
| + | В этой статье я расписал самые важные флаги и опции, которые могут понадобиться в подавляющем большинстве проектов. В следующей же части я расскажу про настройку строгости компилятора. | ||
| + | |||
| + | UPD: Здесь можно прочитать [[https://habr.com/ru/post/557738/|вторую часть статьи]]. | ||
| + | |||
| =====tsconfig.json===== | =====tsconfig.json===== | ||
| ====config==== | ====config==== | ||
| Строка 153: | Строка 502: | ||
| </code> | </code> | ||
| + | |||