Transfer. Original link .
In some cases, the TypeScript
compiler inserts helper functions into the generated JavaScript
code, which are then called during execution. Each such auxiliary function emulates the semantics of a language feature that is not natively supported by browsers yet.
Currently, the following auxiliary functions exist in TypeScript
:
__extends
for inheritance__assign
for the spread
operator__rest
for rest
operator__decorate
, __param
and __metadata
for decorators__awaiter
and __generator
for async/await
For example, if the following code:
import * as React from "react"; export default class FooComponent extends React.Component<{}, {}> { render() { return ( <div>Foo</div> ); } }
compile to ES5
standard, which does not support either a class or an extension, then the output will be:
"use strict"; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var React = require("react"); var FooComponent = (function (_super) { __extends(FooComponent, _super); function FooComponent() { return _super.apply(this, arguments) || this; } FooComponent.prototype.render = function () { return (React.createElement("div", null, "Foo")); }; return FooComponent; }(React.Component)); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = FooComponent;
This is only suitable for simple examples like the one described above. In fact, he has a huge drawback.
The auxiliary function __extends
inserted into the compiled result for each file in which you use class inheritance. This means that for each React
component, a helper function is inserted based on the class.
For an average application size that includes dozens or hundreds of React
components, this will result in a large number of repetitive code only for the __extends
function. This increases the size of the bundle, resulting in an increase in file download time.
This problem is only exacerbated when other helpers are used in the compiled result. The auxiliary functions of __awaiter
and __generator
are huge and make a significant contribution to the size of the bundle. Remember, they are inserted for each file in which you use async/await
.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments)).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; return { next: verb(0), "throw": verb(1), "return": verb(2) }; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } };
--noEmitHelpers
Starting with version 1.5
, TypeScript
supports the --noEmitHelpers
flag. If the compiler sees this flag, TypeScript
will not insert helper functions in the compiled code.
React
component described above compiled with the --noEmitHelpers
flag:
"use strict"; var React = require("react"); var FooComponent = (function (_super) { __extends(FooComponent, _super); function FooComponent() { return _super.apply(this, arguments) || this; } FooComponent.prototype.render = function () { return (React.createElement("div", null, "Foo")); }; return FooComponent; }(React.Component)); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = FooComponent;
Notice that the __extends
function is still being called. In the end, the main thing is that the React
component works. If you use the --noEmitHelpers
flag, it is your responsibility to provide all the necessary helper functions. TypeScript
assumes that they will be available at runtime.
However, it is too laborious to do it manually. You should check which support functions are needed and then somehow make them available in the application. The prospect is not bright! Fortunately, the TypeScript
team has developed a solution.
--importHelpers
and tslib
libraryIn version 2.1
a new flag --importHelpers
, which tells the compiler to import functions from the external library of tslib
, and not to paste them for each file. You can install tslib
just like any other npm package:
npm install tslib --save
Let's recompile our React
component. This time using the --importHelpers
flag:
"use strict"; var tslib_1 = require("tslib"); var React = require("react"); var FooComponent = (function (_super) { tslib_1.__extends(FooComponent, _super); function FooComponent() { return _super.apply(this, arguments) || this; } FooComponent.prototype.render = function () { return (React.createElement("div", null, "Foo")); }; return FooComponent; }(React.Component)); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = FooComponent;
Pay attention to require("tslib")
on the second line and use tslib_1.__extends
on the fifth. This file is no longer auxiliary functions. Instead, the __extends
function __extends
imported from the tslib
module. Thus, each helper is imported only once, and you will not be penalized for using extends
and async/await
in many files.
Source: https://habr.com/ru/post/343818/
All Articles