TypeScript allows to convert most of the ES next features to ES3, ES5, ES6, ES2016, ES2017. Of course, you can also target ES Next. But which version should you target?
Using the highest version allows allows you to write shorter code, and use more readable features, such as async/await, for..of, spread, etc. It's not only shorter, but also easier to debug. For instance, async/await is rewritten by TypeScript to a state machine. So, the call stack is harder to understand, steping into the next statement is not easy because you have to step into the step machine functions. The source map can sometimes helps, but it doesn't solve all issues. You can also blackbox some scripts. For instance, you can blackbox
tslib if you import TypeScript helpers.
So, if you can target ES Next, do it! But unfortunately this is not always possible. Let's see how to choose the right version!
First, you must know which runtime you want to support. Do you need to run you application in a web browser and which one, in NodeJS or in Electron. Depending of this choice, you know the JS flavor you can use. For instance, if you choose Electron, you know it uses Chromium version XXX so you know which functionalities are available. In you use NodeJS, it also use V8, the JS engine of Chromium. So, it easy to know which features are supported. For web browser, it's a little more complicated. You may want to support multiple browsers, and multiple versions of each browser.
You can check which features are supported by the web browsers and js runtime here: https://kangax.github.io/compat-table/es6. Tip: you can change the ES version on the top.
For instance, if you want to target IE11, you'll have to target ES5. If you want to support NodeJS, Edge or Chromium, ES6 is ok.
Once you know which version you want to use, update the
tsconfig.json file to reflect your decision:
"target": "ES2016" // "ES3" (default), "ES5", "ES6"/"ES2015", "ES2016", "ES2017" or "ESNext".
Changing the target version also change the available libraries. For instance, if you target ES5, you cannot use Promise. But Promise is not a feature that must be implemented by the engine. You can use another library to replace them, such as bluebird. This means you can target ES5 and use Promise as long as you add them using an external library. It's the same for
Array.include, and lots of functions.
TypeScript allows to specify which libraries are available. You can select them in the configuration file
You can find the list of available libraries in the TypeScript documentation.
BTW, you can read my previous post to dynamically import polyfills
As I said in the introduction, using a higher version of EcmaScript may help debugging your application. So, it may not be a bad idea to have 2 configurations, one for the development and another one for the release. For instance, the first one can target ES next because you are debugging on a recent browser, while the second one can target ES5 because your customers may use an older browser.
TypeScript supports the configuration inheritance. So, you can create common
tsconfig.json that contains all the settings, and a
tsconfig.dev.json that inherits from
tsconfig.json. You can build using
tsc tsconfig.dev.json. You can read the documentation about configuration inheritance for more information.
If you are using webpack, gulp or any build tool, you may consider the Babel option. The idea is to configure TypeScript to target ES Next, and transpile to another version using Babel. Based on the previous link, Babel allows transpiling more things to a lower ES version than TypeScript. Using webpack, you can also automatically include polyfills with a plugin such as
Choose the configuration that make you the most productive and which will run on your target browsers / runtimes.