Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are babel decorators the same as TypeScript's?

I code with TypeScript a lot, but less babel, I know how TypeScript works on decorators, and babel also support decorators, do they act the same?

like image 390
A-yon Lee Avatar asked Feb 11 '18 19:02

A-yon Lee


People also ask

Is Babel still needed 2022?

Conclusion. Having Babel and TypeScript do part of the source transform seems unnecessarily complicated. So, if you are using both, it is better to use Babel for transpiling and the TypeScript compiler for type checking.

Can Babel Transpile TypeScript?

Babel for transpiling, tsc for types ts file generation. By using babel's support for TypeScript, you get the ability to work with existing build pipelines and are more likely to have a faster JS emit time because Babel does not type check your code.

What are decorators in TS?

A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression , where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.

What are JavaScript decorators?

JavaScript decorators are a relatively new feature in JavaScript that allows adding new behavior to existing functions and objects without modifying their underlying code. You can achieve it by using a special syntax that uses an @ symbol before the function name or object key.


2 Answers

Yes, they are the same, in a sense that they produce the same behavior, but they have different implementations.

Both follow ECMAScript specifications and bring features early to us. You can expect what is on both of them to probably be supported by node or the browser in the future.

Code:

function f() {
  console.log("f(): evaluated");
  return function (target, propertyKey, descriptor) {
      console.log("f(): called");
  }
}

function g() {
  console.log("g(): evaluated");
  return function (target, propertyKey, descriptor) {
      console.log("g(): called");
  }
}

class C {
  @f()
  @g()
  method() {}
}

new C().method();

TypeScript output:

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function f() {
    console.log("f(): evaluated");
    return function (target, propertyKey, descriptor) {
        console.log("f(): called");
    };
}
function g() {
    console.log("g(): evaluated");
    return function (target, propertyKey, descriptor) {
        console.log("g(): called");
    };
}
class C {
    method() { }
}
__decorate([
    f(),
    g()
], C.prototype, "method", null);
new C().method();

Babel output:

"use strict";

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _dec, _dec2, _desc, _value, _class;

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function (key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;

  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }

  desc = decorators.slice().reverse().reduce(function (desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);

  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }

  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }

  return desc;
}

function f() {
  console.log("f(): evaluated");
  return function (target, propertyKey, descriptor) {
    console.log("f(): called");
  };
}

function g() {
  console.log("g(): evaluated");
  return function (target, propertyKey, descriptor) {
    console.log("g(): called");
  };
}

var C = (_dec = f(), _dec2 = g(), (_class = function () {
  function C() {
    _classCallCheck(this, C);
  }

  _createClass(C, [{
    key: "method",
    value: function method() {}
  }]);

  return C;
}(), (_applyDecoratedDescriptor(_class.prototype, "method", [_dec, _dec2], Object.getOwnPropertyDescriptor(_class.prototype, "method"), _class.prototype)), _class));


new C().method();

Output after run:

> ts-node ts-example.ts
f(): evaluated
g(): evaluated
g(): called
f(): called

> node babel-example.js
f(): evaluated
g(): evaluated
g(): called
f(): called
like image 181
BrunoLM Avatar answered Oct 09 '22 13:10

BrunoLM


No, they are different. Babel don't support parameter decorators, and TS's property decorators don't support the initializer for a property.

like image 23
unadlib Avatar answered Oct 09 '22 13:10

unadlib