Support Ukraine 🇺🇦Help Ukrainian ArmyHumanitarian Assistance to Ukrainians

TypeScript lib vs target: What's the difference?


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?

1 Answer


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).

claritician © 2022