- ✅
compilerOptions.jsx
- ✅
compilerOptions.lib
- ✅
compilerOptions.target
- ✅
compilerOptions.downlevelIteration
- ✅
compilerOptions.experimentalDecorators
- ✅
compilerOptions.importHelpers
- ✅
compilerOptions.jsxFactory
- ✅
compilerOptions.allowJs
- ✅
compilerOptions.checkJs
- ❌
compilerOptions.maxNodeModuleJsDepth
- ❌
compilerOptions.allowSyntheticDefaultImports
- ❌
compilerOptions.allowUnreachableCode
- ❌
compilerOptions.allowUnusedLabels
- ❌
compilerOptions.alwaysStrict
- ❌
compilerOptions.baseUrl
- ❌
compilerOptions.build
- ❌
compilerOptions.charset
- ❌
compilerOptions.checkJs
- ❌
compilerOptions.composite
- ❌
compilerOptions.declaration
- ❌
compilerOptions.declarationDir
- ❌
compilerOptions.declarationMap
- ❌
compilerOptions.diagnostics
- ❌
compilerOptions.disableSizeLimit
- ❌
compilerOptions.emitBOM
- ❌
compilerOptions.emitDeclarationOnly
- ❌
compilerOptions.emitDecoratorMetadata
- ❌
compilerOptions.esModuleInterop
- ❌
compilerOptions.extendedDiagnostics
- ❌
compilerOptions.forceConsistentCasingInFileNames
- ❌
compilerOptions.incremental
- ❌
compilerOptions.inlineSourceMap
- ❌
compilerOptions.inlineSources
- ❌
compilerOptions.init
- ❌
compilerOptions.isolatedModules
- ❌
compilerOptions.keyofStringsOnly
- ❌
compilerOptions.listEmittedFiles
- ❌
compilerOptions.listFiles
- ❌
compilerOptions.locale
- ❌
compilerOptions.mapRoot
- ❌
compilerOptions.module
- ❌
compilerOptions.moduleResolution
- ❌
compilerOptions.newLine
- ❌
compilerOptions.noEmit
- ❌
compilerOptions.noEmitHelpers
- ❌
compilerOptions.noEmitOnError
- ❌
compilerOptions.noErrorTruncation
- ❌
compilerOptions.noFallthroughCasesInSwitch
- ❌
compilerOptions.noImplicitAny
- ❌
compilerOptions.noImplicitReturns
- ❌
compilerOptions.noImplicitThis
- ❌
compilerOptions.noImplicitUseStrict
- ❌
compilerOptions.noLib
- ❌
compilerOptions.noResolve
- ❌
compilerOptions.noStrictGenericChecks
- ❌
compilerOptions.noUnusedLocals
- ❌
compilerOptions.noUnusedParameters
- ❌
compilerOptions.outDir
- ❌
compilerOptions.outFile
- ❌
compilerOptions.paths
- ❌
compilerOptions.preserveConstEnums
- ❌
compilerOptions.preserveSymlinks
- ❌
compilerOptions.preserveWatchOutput
- ❌
compilerOptions.pretty
- ❌
compilerOptions.project
- ❌
compilerOptions.reactNamespace
- ❌
compilerOptions.removeComments
- ❌
compilerOptions.resolveJsonModule
- ❌
compilerOptions.rootDir
- ❌
compilerOptions.rootDirs
- ❌
compilerOptions.showConfig
- ❌
compilerOptions.skipLibCheck
- ❌
compilerOptions.sourceMap
- ❌
compilerOptions.sourceRoot
- ❌
compilerOptions.strict
- ❌
compilerOptions.strictBindCallApply
- ❌
compilerOptions.strictFunctionTypes
- ❌
compilerOptions.strictPropertyInitialization
- ❌
compilerOptions.strictNullChecks
- ❌
compilerOptions.strictExcessPropertyErrors
- ❌
compilerOptions.suppressImplicitAnyIndexErrors
- ❌
compilerOptions.traceResolution
- ❌
compilerOptions.tsBuildInfoFile
- ❌
compilerOptions.types
- ❌
compilerOptions.typeRoots
- ❌
compilerOptions.watch
- Configuration file for
tsc
, the TypeScript compiler. - Indirectly used by
tslint
and therefore editor plugins that rely on TSLint (i.e., your IntelliSense editor errors may be due to an incorrectly configuredtsconfig.json
).
- By default,
tsc
searches for a file namedtsconfig.json
in the current working directory.- If it can't find it there, it traverses up the directory hierarchy until it finds one.
- If it doesn't find one, it falls back to a default configuration.
- Multiple
tsconfig.json
files in sibling/nested folders of a project shouldn't cause problems,tsc
will just follow the algorithm above. - Editors may, however, get confused by multiple
tsconfig.json
files, or at least interact with them in non-intuitive ways. For example, when opening the root directory of a monorepo, VS Code will only read the top-leveltsconfig.json
file regardless of where the closest config file is located relative to the location of your currently open file in the directory hierarchy.
.tsx?
files →tsc
→.js
files- By default,
tsc
compiles whole projects rather than individual files. Runningtsc
on the command line will compile every.ts
file (and optionally.tsx
files) in the current directory and every subdirectory. Compiled files will be emitted to wherever has been configured intsconfig.json
.
- By default,
.tsx?
files →webpack
→tsc
(viats-loader
) →.js
files- For Node >= 8.10 targets, can use
target: 'ES2016'
incompilerOptions
- For browser targets, can use
target
andlib
options while manually providing polyfills if necessary (see below), or can chaints-loader
withbabel-loader
and let Babel handle polyfills - Note:
tsc
never introduces polyfills but can introduce compatibility helpers for supproting certain syntaxes (see below)
- For Node >= 8.10 targets, can use
.tsx?
files →webpack
->tsc
(viats-loader
) →babel
(viababel-loader
) →.js
files- Probably not necessary for Node targets
- For browser targets, can use
target: 'ES2018'
and let Babel handle polyfills and down-compiling
.tsx?
files →webpack
→babel
(viababel-loader
) →.js
files- Uses Babel rather than
tsc
for compilation. - Pros: simpler toolchain (one less loader and compiler), supposedly faster especially in development when rapidly iterating because it skips type checking
- Cons: skips type checking, doesn't support
const enum
(inconvenient) or type metadata (breaks major TypeScript ecosystem packages like TypeORM)
- Uses Babel rather than
.tsx?
files →tslint
(via CLI or editor) →tsc --noEmit
→ errors (no files emitted)
When configuring which language your TypeScript code compiles into, it's important to understand how compatibility is modeled.
"Language compatibility" is a broad concept indicating whether some code conforms to a particular version of a given language. For example, if we say that your code is compatible with ES5, we might mean that it doesn't use ES2015+ features such as promises. We might alternatively mean that your source code uses ES2015+ features but is compiled into code that can run in environments that only support ES5 by using polyfills or changing the syntax. A more precise way to talk about compatibility is to talk in terms of library and syntax support.
This concept refers to whether the compiler allows certain non-syntactical features of a language. For example, in order to use promises, we need support for the ES2015.Promises API, which is normally provided by the execution environment as a library. Features that need library support can be thought of as those that must have a polyfill to be backward compatibile because they rely on new, implementation-specific functions.
You must specify what language libraries need to be supported when using TypeScript in order to avoid compiler errors, but since tsc
doesn't inject polyfills it can't down-compile source code that relies on them. If you want to use a feature that requires library support you can take one of three approaches:
- Pick a language version that's completely supported by your target execution environment (e.g., ES5 is a safe bet for browsers) and use
compilerOptions.target
by itself to set the target language. This configuration effectively tells the compiler both that you're writing in that language and that you want it to compile into the same language. The compiler will raise an error if you use an unsupported feature, therefore you must limit yourself to whichever features are supported by the target language. - Pick a language version that's completely supported by your target execution environment, use
compilerOptions.target
to set the target language, and also usecompilerOptions.lib
to indicate the language libraries that will be available at runtime regardless of the target language. Compilation will succeed, but if you use features supported bycompilerOptions.lib
but not supported bycompilerOptions.target
, you must introduce polyfills manually to make sure that the compiled code runs correctly. - Pick a language version that supports all of the features you want irrespective of whether your target environment supports them (e.g., ES2018 is widely unsupported but has the very useful object spread operator) and use
compilerOptions.target
by itself to set the target language. Your compiled code won't run correctly by itself, but you can use a tool like Babel to further down-compile your emitted code and inject the necessary polyfills rather than doing it manually.
This concept refers to being able to use purely syntactical features of a language. For example, in order to use classes, we would need compatibility with the ES2015 language since that's the standard that introduced that features. However, because classes are purely syntactical, the compiler can down-compile them without introducing a full-blown polyfill.
You can safely use features that only require syntax support by setting your target language with compilerOptions.target
without any further work. Regardless of your targeted language version because tsc
will always down-compile when necessary.
TypeScript down-compiles syntax features by injecting language compatibility helper functions into your compiled code, which aren't exactly full-blown polyfills but still add some complexity. This behavior is rarely desirable because the injected code is duplicated anywhere that the compiler had to down-compile. You can therefore use the compilerOptions.importHelpers
option to cause tsc
to link to the NPM package tslib
using injected import
's (or require
's, if your target is commonjs
). You can either execute the compiled code as-is if your environment supports tslib
, or you can bundle the dependency using Webpack, which will still result in a smaller bundle size.
(Reminder: ES5 → ES6/ES2015 → ES2016 → ES2017 → ES2018 → ESNext. ES6 is the old name for ES2015, ESNext is a moving target that represents the bleeding edge of the ECMAScript standard.)
target: 'ES5'
- Your code will be compiled into ES5
- ES5 library features ARE supported by the compiler, WON'T raise errors and WON'T be down-compiled
- ES5 syntax features ARE supported by the compiler, WON'T raise errors and WON'T be down-compiled
- ES2015+ library features AREN'T supported by the compiler, WILL raise errors and WON'T be down-compiled
- ES2015+ syntax features ARE supported by the compiler, WON'T raise errors and WILL be down-compiled
target: 'ES2015'
- Your code will be compiled into ES2015
- ES2015 library features ARE supported by the compiler, WON'T raise errors and WON'T be down-compiled
- ES2015 syntax features ARE supported by the compiler, WON'T raise errors and WON'T be down-compiled
- ES2016+ library features AREN'T supported by the compiler, WILL raise errors and WON'T be down-compiled
- ES2016+ syntax features ARE supported by the compiler, WON'T raise errors and WILL be down-compiled
target: 'ES5', lib: 'ES2015'
- Your code will be compiled into ES5
- ES2015 library features ARE supported by the compiler, WON'T raise errors and WON'T be down-compiled
- Because ES2015 features won't be down-compiled and will be included as-is, it's your responsibility to introduce the appropriate polyfills to ensure that your compiled code runs in your target environment if necessary
- ES2015 syntax features ARE supported by the compiler, WON'T raise errors and WILL be down-compiled
- ES2016+ library features AREN'T supported by the compiler, WILL raise errors and WON'T be down-compiled
- ES2016+ syntax features ARE supported by the compiler, WON'T raise errors and WILL be down-compiled
TypeScript also supports a few language features that don't fit neatly within the scope of compilerOptions.target
or compilerOptions.lib
through one-off configs.
compilerOptions.experimentalDecorators
enables support for decorators (i.e., @autobind
).
Decorators are used widely throughout the JavaScript ecosystem. Despite this fact, they aren't yet part of any official ECMAScript standard (as of writing, they are at stage 2 or "draft", see https://github.com/tc39/proposal-decorators). Apps using decorators typically rely on Babel (see https://babeljs.io/docs/en/babel-plugin-proposal-decorators).
Decorator support isn't controlled by compilerOptions.target
even though it can be thought of as a purely syntactical feature because it isn't actually part of any language. Yet not including support would be highly impractical given how commonly they're used (again, thanks to Babel). Therefore, tsc
presumably supports decorators using the compilerOptions.experimentalDecorators
config as a pragmatic compromise.
compilerOptions.downlevelIteration
enables full support for the ES2015+ iteration protocol (i.e., for...of
loops) when targeting ES5 and lower.
for...of
by itself is a syntax feature that can be rewritten using index-based loops, hence it's already supported using compilerOptions.target
. However, ES2015 is smarter about how for...of
iterates depending on the iterable type. For example, strings in ES2015 are iterated over their code points rather than their characters. compilerOptions.downlevelIteration
allows for using this more intelligent behavior in ES5 and below. Without it, targeting ES5 or earlier versions will use the standard "dumb" behavior, causing for...of
loops to incorrectly iterate over things like strings.
Since this feature only affects ES5 and below, and because the correct, spec-compliant ES5 behavior is actually the undesirable one, it's not controlled by compilerOptions.target
. Also, this behavior isn't implemented as part of an ES2015 library, so it's not controlled by compilerOptions.lib
. See https://mariusschulz.com/blog/typescript-2-3-downlevel-iteration-for-es3-es5 for more details.
TypeScript code mixed with JSX is saved in .tsx
files and can by handled by tsc
by using the compilerOptions.jsx
setting.
In general, you'll want to set the config to preserve
, which causes tsc
to pass through any JSX into the compiled files, which are emitted as .jsx
files. These won't run on their own, but Babel will compile the .jsx
files into .js
, which will then be included as part of your bundle if using Webpack. You'll want to set the config to react
or react-native
if you're not using Babel to convert the JSX into React API (e.g., React.createElement
) calls and compile the code into .js
files. See the helpful table here: https://www.typescriptlang.org/docs/handbook/jsx.html#basic-usage
A notable edge case is if you're using server-side rendering, in which case you may not be using Babel and would want to set compilerOptions.jsx
to React so that the compiled code can run in your Node environment.
Finally, if you'd like tsc
to transform your JSX into API calls without using Babel but you're not using React or React Native (e.g., you're using Preact), compilerOptions.jsxFactory
allows you to control the function that's used for the transformation. This defaults to React.createElement
, but you could set it to h
for Preact, for example. Two things to note when setting this option:
- If you set this option, you must also counterintuitively set
compilerOptions.jsx
to'react'
for it to have any effect. Think ofcompilerOptions.jsx = 'react'
as strictly meaning "transform my JSX into API calls, by default React but potentially something else" rather than literally "transform my JSX into React API calls." - It's also possible to set this option on a per-file basis using the
/** @jsx */
pragma at the top of individual files (e.g.,/** @jsx h */
for Preact). This approach can be helpful in situations where you're mixing multiple JSX-compatible libraries sincecompilerOptions.jsxFactory
specifies the same function for all JSX transformations across all files.
See https://mariusschulz.com/blog/typescript-2-8-per-file-jsx-factories for more details.
The TypeScript compiler by default only handles .ts
, .tsx
and .d.ts
(i.e., TypeScript) files. However, since projects often have a mixture of TypeScript and JavaScript, tsconfig.json
has several options for processing .js
and .jsx
files, as well. Some of these options can help replace the need for Babel, leading to a simplified toolchain, or they can be enabled as part of an incremental migration strategy from JavaScript to TypeScript.
compilerOptions.allowJs
tells the compiler to process .js
and .jsx
files. The compiler will apply whatever transformations (e.g., syntax compatibility helpers, JSX to React API calls) that it would normally apply to .ts
and .tsx
files. If these transformations are enough to run your code on your target execution environment, you may be able to dispense with Babel altogether if you're using Babel just for your JavaScript files. You can also take the approach of enabling this option while you gradually rewrite JavaScript in TypeScript, helping ease the migration.
Another benefit of enabling compilerOptions.allowJs
is that downstream utilities that rely on tsc
will process your JavaScript files. This behavior is especially useful for getting tslint
to lint your JavaScript files. If you're using eslint
for your JavaScript files, you could potentially get rid of it and just use tslint
for everything, depending on your needs and your configuration.
"Type checking JavaScript" may sound like an oxymoron at first blush--after all, isn't that language's lack of types the reason why TypeScript exists?
Nevertheless, tsconfig's compilerOptions.checkJs
option enables partial type safety in vanilla JavaScript. When set to true
, TypeScript will use a variety of methods to infer type information, most of all from JSDoc annotations. This setting can be helpful in all situations involving JavaScript files, but it really shines for code bases that have a complete set of JSDoc comments with documentation for parameter types, etc.
JavaScript type checking is disabled by default. You can selectively enable type checking while leaving compilerOptions.checkJs
unset or false
by adding // @ts-check
to whichever .js
and .jsx
files you want checked. Conversely, if you've enabled compilerOptions.checkJs
, you can add the // @ts-nocheck
to selectively disable type checking when there are too many false positives. (NB: // @ts-check
and // @ts-nocheck
must be at the top of the file and applies to the whole file. There currently isn't a way to enable or disable checking on particular lines. Also, // @ts-nocheck
only works on JavaScript files and has no effect on TypeScript files.)
See https://github.com/Microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files for details on how compilerOptions.checkJs
works.
- Controls which language your code gets compiled into AND syntax support
- DOESN'T introduce polyfills
- DOES introduce language compatibility helpers when down-compiling certain syntactical features (e.g., classes, async/await)
- Recommendation
- If you're going to further compile your emitted code with Babel, set to whichever ECMAScript version supports all the features that you're using (e.g.,
ES2018
) regardless of compatibility with your runtime environment - If you're going to run the emitted code without further compilation, set to whichever ECMAScript version is supported by your runtime environment (e.g.,
ES2016
for Node >=8.10,ES2015
orES5
for web browsers)
- If you're going to further compile your emitted code with Babel, set to whichever ECMAScript version supports all the features that you're using (e.g.,
"I want to compile code that's written in X version of JavaScript but I may also use certain syntaxes that are only available in later versions."
- Controls library support (DOESN'T control which language your code gets compiled into NOR syntax support)
- DOESN'T introduce polyfills
- DOESN'T introduce language compatibility helpers (that's the responsibility of
compilerOptions.target
, see above) - Can be combined with
compilerOptions.target
to allow the compiler to compile code with advanced language features without errors, even if the target language version doesn't support those features - Recommendation
- If you're going to further compile your emitted code with Babel, don't set this option at all (the default is to set to whatever version is set by
compilerOptions.target
). Just make sure to configure Babel to inject any necessary polyfills. - If you're going to run the emitted code without further compilation, set to whichever ECMAScript version or library subset supports the features you use, then manually include those polyfills in your source code.
- If you're going to further compile your emitted code with Babel, don't set this option at all (the default is to set to whatever version is set by
"I want to compile code that's written in X version of JavaScript and I don't care whether the target version supports all the features that I'm using because I will make sure that those features are supported at runtime (e.g., with polyfills that I introduce manually or through Babel)."
- Controls whether language compatibility helpers introduced when down-compiling syntax features are inlined in the emitted code or whether they're imported at runtime
- Recommendation
- If you're going to bundle your code using a tool like Webpack or if you're going to run in an environment where you can import/require packages (e.g., Node), set this to
true
since inlining will lead to duplicated helper code wherever the compiler had to down-compile. This case is probably the most common one. - If you're going to run your code without bundling and in an environment that doesn't have access to
tslib
, then set this tofalse
.
- If you're going to bundle your code using a tool like Webpack or if you're going to run in an environment where you can import/require packages (e.g., Node), set this to
"I want to ensure that any injected helper code isn't duplicated by linking to an external library,
tslib
, at runtime or when I bundle my code."
or
"I want to ensure that any injected helper code doesn't ever depend on an external library."
- Controls whether decorator syntax (e.g.,
@autobind
) is supported - Recommendation
- Set to
true
since decorators are used very frequently in JS. - Note that as of writing (April 23rd, 2019, there are differences between the current ECMAScript draft standard for decorators and TypeScript's implementation. For most use cases, however, the specs are compatible.
- Set to
- Controls whether code compiled with an ES3/ES5 target uses the ES2015 and later iterable protocol/
for...of
loop behavior (e.g., when iterating over strings in afor...of
loop, does the code iterate over code points rather than characters?) - Recommendation
- Set to
true
since the ES3/ES5 behavior is generally considered broken. - Only set to
false
if you need to exactly match the original ES3/ES5 behavior. - May not make any difference even if you set this to
false
if you run your compiled code in a recent environment that implements the ES2015 iterable protocol since thefor...of
syntax is identical.
- Set to
- Controls whether JSX code is compiled into React/React Native API calls or whether it's preserved as raw JSX; also, controls the extension of emitted files (
.tsx
→.js
vs..tsx
→.jsx
) - Recommendation
- If you're using Babel, set to
preserve
to have Babel handle conversion into React API calls and.js
. This is probably the most common case. - If you're not using Babel (e.g., many server-side rendering setups), use
react
orreact-native
.
- If you're using Babel, set to
"I want to make sure any JSX code is passed through by
tsc
for later processing by Babel or another tool."
or
"I want
tsc
to take care of transforming JSX code into API calls, by default for the React API using React.createElement, but potentially using a different function call (e.g.,h
for Preact) if I also setcompilerOptions.jsxFactory
."
- Controls what function call
tsc
uses to replace JSX code with. Defaults toReact.createElement
but can be replaced with anything (e.g.,h
for Preact). - Only has an effect if you set
compilerOptions.jsx
to'react'
. - Recommendation
- Only set if you're writing JSX for a library other than React/React Native and you want
tsc
to handle your JSX transforms (e.g., you're not using Babel to transform JSX into executable code). - You can also specify a different function call on a per-file basis using the
/** @jsx */
pragma. This approach can be helpful in projects that mix different JSX-consuming libraries (e.g., if you're using React and Preact) since settingcompilerOptions.jsxFactory
will apply the same function call to all transformations across all files. - See https://mariusschulz.com/blog/typescript-2-8-per-file-jsx-factories for more details.
- Only set if you're writing JSX for a library other than React/React Native and you want
"I want
tsc
rather than Babel or another tool to handle my JSX transformations and I'm not using React or React Native."
- Controls whether
.js
and.jsx
files are processed bytsc
. - Any transformations that would normally be applied to
.ts
or.tsx
files (e.g., syntax compatibility helpers, JSX-to-React API calls) are applied. - Recommendation
- Set to
true
by default, especially if you'd like to standardize your toolchain on just usingtsc
and/ortslint
(i.e., removing Babel and/or eslint). - Consider setting to
false
if you have complicated Babel or eslint configurations and compiling your JavaScript files withtsc
may raise errors that contradict your settings elsewhere.
- Set to
- Controls whether
tsc
attempts limited type checking on JavaScript files by inferring types, especially from JSDoc annotations. - See https://github.com/Microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files for more details on how
tsc
's JavaScript type checking works. - Recommendation
- Set to
true
by default, especially if you have complete JSDoc type annotations, and add// @ts-nocheck
to the top of problematic JavaScript files where type checking seems to result in false positives. - Alternatively, set to
false
or leave unset and add// @ts-check
to JavaScript files that you want type checked as part of an iterative migration strategy.
- Set to