Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is ES7/array polyfill needed despite the tsconfig target is set to ES5

I have the following settings in thetsconfig.json. I added "es2017" to use Array.includes.:

{
  "compilerOptions": {
    "lib": [
      "es6",
      "es2017",
      "dom"
    ],
    "module": "es6",
    "target": "es5"
  }
}

Now, I realized, that I have to add import 'core-js/es7/array'; to the polyfills.ts, to use Array.includes also for the Internet Explorer 11. The target in the tsconfig.json is set to es5, which does not have Array.includes.

Why do I need to add the polyfill?

like image 230
BuZZ-dEE Avatar asked May 23 '19 13:05

BuZZ-dEE


People also ask

What does Tsconfig target do?

The target setting changes which JS features are downleveled and which are left intact. For example, an arrow function () => this will be turned into an equivalent function expression if target is ES5 or lower. Changing target also changes the default value of lib .

What is target ES6?

target. ES6 provides a metaproperty named new. target that allows you to detect whether a function or constructor was called using the new operator.

What TypeScript does target use?

By default, the target is es2017 , which is supported in modern browsers.


1 Answers

TypeScript does not auto-polyfill code (see microsoft/TypeScript#3101). The "official" reason from the relevant GitHub issue seems to be, as @RyanCavanaugh said:

Having the compiler try to figure out which [ES20XX] methods you need, and where to emit them, and when, with controls for people who don't want the polyfills emitted, and ways to change where those polyfills come from, etc, is a big mess that isn't justified by the potential gains over simply including a normal [ES20XX] polyfill library in your script context.

And, as it's mentioned in that issue, emitting runtime code is a non-goal of TypeScript:

[Non-Goal #]6. Provide additional runtime functionality or libraries. Instead, use TypeScript to describe existing libraries.


I'm guessing that some of the confusion comes from the fact that TypeScript does downlevel some language features when targeting earlier EcmaScript versions. The main criterion used when determining if a feature will be emitted as downleveled code or whether it needs a polyfill is syntax:

If the new language feature is syntactically invalid in the targeted version, then it will either be downleveled or you will get a compile time warning. You can't polyfill invalid syntax. For example, class Foo {} is not and cannot be valid ES5 code... so it will be converted into a constructor function instead when targeting ES5.

If, on the other hand, the language feature is syntactically valid in the targeted version, it will be emitted as-is with no warning. So [1,2,3].includes(0) is perfectly valid ES5 code in terms of syntax. Assuming that someone adds an Array.prototype.includes method to an ES5 engine, it will even work at runtime. So it is emitted as-is. Note that when you include es2017 in your lib compiler options, you're telling TypeScript that the runtime will support ES2017 typings, and so there is no compile-time warning. Adding typing libraries does not do anything to the runtime itself... so you're responsible for polyfilling/shimming anything you need. From the compiler's perspective it can't deal with the situation where you lied to it about what methods exist at runtime. Obviously that's not much consolation for someone frustrated by a runtime error, though.

Oh well, it is what it is, I guess.


Hope that helps. Good luck!

like image 76
jcalz Avatar answered Nov 15 '22 20:11

jcalz