john
Jul 10 2021 at 10:20 GMT
I am confused about the difference between the lib
and target
TypeScript compiler options.
From the docs, lib
specifies a set of bundled library declaration files that describe the target runtime environment, while target
sets the JavaScript language version for emitted JavaScript and includes compatible library declarations.
I understand that these compiler options are used to specify the target environment so that TypeScript can transpile modern JavaScript features to an older version of JavaScript, but I miss the difference. If my target environment are browsers that run ES5, should I specify ES5
as the target
, the lib
, or both?
Travis
Jul 10 2021 at 13:11 GMT
Initially, there was only the target
compiler option for specifying the target runtime environment.
If your target is ES5, you would specify "target": "es5"
in your tsconfig.json
.
First of all, this would mean that any JavaScript syntax that is not supported in ES5 would be transpiled by TypeScript to ES5. For example, if in your code you use const
and arrow functions (which are part of ES6):
const add = (a: number, b: number) => a + b;
The TypeScript compiler would transpile them to var
and function
:
var add = function(a, b) {
return a + b;
};
Second, you would not be allowed to use JavaScript APIs that are not supported in an ES5 environment. For example, Promise
is only supported in ES2015 (or ES6), so you cannot use promises because TypeScript will not generate polyfills for them.
return Promise.resolve(value);
'Promise' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the 'lib' compiler option to es2015 or later.
return Promise.resolve(value);
~~~~~~~
TypeScript only transpiles new JavaScript syntax like arrow functions and async functions, but it does not provide polyfills for JavaScript APIs, like Promise
, array.find
, Map
, etc. (unlike Babel).
Therefore, it is up to you to include polyfills for JavaScript APIs that your runtime environment might not support. So, if you want to use promises in an ES5 environment, you would include a Promise
polyfill.
However, you will run into a problem. Even though you're importing a Promise
polyfill, TypeScript does not know that, and shows the error we saw before. That's why the lib
option was introduced. lib
tells TypeScript which library APIs will be available in your runtime environment.
By default, the value of lib
is derived from the target
. So, if the target
is "es5"
, then TypeScript assumes that the runtime environment is an ES5 browser, which understands ES5 JavaScript APIs, and DOM APIs. More concretely, the default lib
in this case would include "dom"
and "es5"
.
Since you know that you're providing a Promise
polyfill, you would manually specify lib
set to ["dom", "es5", "es2015.promise"]
. This will include type declarations for ES2015 promises and allow you to use promises without TypeScript complaining.
Another use case for lib
is to not have DOM type definitions in a NodeJS project, as NodeJS does not have things like window
and document
, so you shouldn't be allowed to use them. In this case you would manually set target
to "es5"
and lib
to ["es5"]
.
However, if you're targeting NodeJS, your runtime environment will support newer versions of JavaScript than ES5. For example, if Node 12 is the oldest version of Node that want to you support, then you would set target
to "es2019"
as Node 12 supports ES2019 syntax and you would set lib
to ["es2019", "es2020.promise", "es2020.bigint", "es2020.string"]
because Node 12 supports all the JavaScript APIs available in ES2019 (like Object.fromEntries
) along with ES2020 APIs related to promises, big int, and strings (like string.matchAll
).
You can find the values for target
and lib
for common platforms (like Node) and their versions in the tsconfig/bases repository (which is how I found the correct target
and lib
for Node 12 shown above).