Using latest JavaScript features in TypeScript, such as ES2018
The story is a bit more complex, and we should begin by separating it in two: language features and runtime features.
ES Language Features
When we say language features we mean changes to the core JavaScript language syntax. For example ES 2015
adds support for classes, arrow functions (=>
), and for-of
iteration
Typescript tries to implement all stable language features proposals as soon as possible and will down-compile them to the ES version specified as the target
option to the compiler. So this means if you have the latest Typescript compiler, which adds support for a fresh new ES 2019
language feature, you will be able to down-compile it all the way down to ES3
. Typescript will emit the code necessary to make such features work in whatever version of ES you are targeting.
And you can see this in action now. If you target ES5
, arrow functions are compiled into regular function
s and use a _this
local variable to captures this
. Classes are compiled to a function and the apropriate fields on the prototype
set.
ES Runtime Features
In addition to the language features, we have certain runtime features that describe what built-in object types are available, and what methods and fields those runtime objects have. Examples of new object types in recent versions of ES
would be Promise
or Proxy
.
Typescript does not provide poly-fills for such features, if the runtime does not offer support for these you will need to come with your own poly-fill implementation if you want to use them.
Typescript does however need to know what built-in objects exist at runtime and what their methods/fields are, this is where the lib
option comes in. It allows you to specify what the runtime environment will look like.
So you could for example target es5
, but specify that the runtime will have all the build-in objects in conformance with the es2015
standard (some might be implemented by the runtime itself, others may be added by you through poly-fills)
The intersection of the two
The division above is a simplification, in that some language features rely on the existence of certain built-in objects and methods.
For example, the async/await
language feature relies on the existence of promises. So if you use async/await
and target es5
you will get an error that the Promise
constructor does not exist. If you target es5
but you specify lib: [ 'es2015', 'dom' ]
you will no longer get an error as you have told the compiler that even though you wish to down compile to es5
, at runtime the Promise
constructor will exist as per the es2015
runtime specification represented in that particular lib(not the compiler's problem how this will happen, poly-fills or built-in runtime behavior).
Generally if such a reliance exists, the typescript compiler will issue an error that certain types are missing and you can upgrade your lib, or change your target (which will change the default libs used), but you will have to ensure that the runtime has the necessary support.
The exceptions
It might not always be possible to down-compile language features all the way down to es3
(either because of missing runtime features, or just because of the high cost of implementing the feature does not make it a priority for the compiler team). An example would be property accessors (get
/set
) when targeting es3
, which is unsupported. The compiler should warn you however if you are using an unsupported language feature/ target combination.