📜 ⬆️ ⬇️

TypeScript: tslib library

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 :



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 }; } }; 

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


Flag - --importHelpers and tslib library


In 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