compilationtypescriptecmascript-6traceur

What is the advantage of using both TypeScript and Traceur?


You can configure TypeScript to output either ES5 or ES6. As long as you want to run your application on a platform that does not natively support ES6 you must compile the ES6 to ES5 using a compiler like Traceur (and including the Traceur runtime library).

Is there any advantage of doing this rather than simply telling TypeScript to output ES5? (I don't expect that the application will ever target native ES6 platforms only)

As far as I have understood you cannot write a program in TypeScript (1.5) that cannot run on ES5 (given that the program compiles and you include the correct libraries). Am I wrong?


Solution

  • Reasons to use Babel or Traceur over TypeScript

    So far, the team of Typescript chose not to make the generated code dependent of a runtime. Some features of ES6 can easily be used with TS through polyfills (example: ES6 Promises). Other features require the cooperation of the transpiler and a polyfill (example: ES6 generators). Using a generator with TS is possible (since TS 1.6) but the target must be ES6. That's a good reason to use Babel or Traceur.

    Reasons to not use Babel or Traceur over TypeScript

    But there are other good reasons for not using Babel and Traceur. Just try to transpile some ES6 code.

    The ES6 code:

    let list = ['ab', 'cd'];
    for (let item of list) {
        console.log(item);
    }
    

    ES5 produced by TypeScript (using the Playground):

    var list = ['ab', 'cd'];
    for (var _i = 0; _i < list.length; _i++) {
          var item = list[_i];
          console.log(item);
    }
    

    ES5 produced by Traceur (using the REPL):

    $traceurRuntime.ModuleStore.getAnonymousModule(function() {
        "use strict";
        var list = ['ab', 'cd'];
        var $__4 = true;
        var $__5 = false;
        var $__6 = undefined;
        try {
          for (var $__2 = void 0,
              $__1 = (list)[$traceurRuntime.toProperty(Symbol.iterator)](); !($__4 = ($__2 = $__1.next()).done); $__4 = true) {
            var item = $__2.value;
            {
              console.log(item);
            }
          }
        } catch ($__7) {
          $__5 = true;
          $__6 = $__7;
        } finally {
          try {
            if (!$__4 && $__1.return != null) {
              $__1.return();
            }
          } finally {
            if ($__5) {
              throw $__6;
            }
          }
        }
        return {};
    });
    //# sourceURL=traceured.js
    

    ES5 produced by Babel (using the REPL):

    'use strict';
    
    var list = ['ab', 'cd'];
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;
    
    try {
        for (var _iterator = list[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var item = _step.value;
    
            console.log(item);
        }
    } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
    } finally {
        try {
            if (!_iteratorNormalCompletion && _iterator['return']) {
                _iterator['return']();
            }
        } finally {
            if (_didIteratorError) {
                throw _iteratorError;
            }
        }
    }
    

    The solutions from Traceur and Babel are ugly, because the variable list could be an ES6 iterable and these transpilers aren't aware of the types. TypeScript infers that the type of list is an array string[] and it produces just the code for the array.