babel: [plugin-transform-typescript] constructor auto-assign not working with plugin-transform-classes

The following doesn’t seem to work, but is also not listed in the readme

If it’s not possible to fix/implement, it would be good to throw an error when used, and mention it there.

Input Code

class Foo {
  constructor(public type: string) {
    console.log('type', this.type);
  }
}
new Foo('bar');

Babel/Babylon Configuration (.babelrc, package.json, cli command)

{
  "presets": [
    ["@babel/env", {
      "targets": {
        "browsers": ["last 2 versions"],
        "node": "8"
      }
    }],
    "@babel/preset-stage-3",
    "@babel/typescript"
  ]
}

Expected Behavior

  • have this.type = type added as first line in the constructor, or
  • throw an error that this syntax is not supported (so it won’t be used by accident, resulting in incorrect transpiled code)

TypeScript transpiles to:

var Foo = /** @class */ (function () {
    function Foo(type) {
        this.type = type;
        console.log('type', this.type);
    }
    return Foo;
}());
new Foo('bar');

Current Behavior

Constructor function without any assignment, so the type parameter is never set.

Context

Wanting to make use of TypeScript type checking, but also (more up-to-date) babel transpilation, without having to do a 2-step-compilation pass. Every unsupported feature should at least be detected with throwing an error, and documented. Without that, people could use that unsupported code by accident without knowing, resulting in non-working code.

Your Environment

software version(s)
Babel 7.0.0-beta.35
node 8.9.1
npm 5.5.1 (yarn 1.3.2)
Operating System OSX

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 14
  • Comments: 15 (2 by maintainers)

Most upvoted comments

Is there going to be any proper solution for this one?

I’ve also ran into this.

I would prefer to not have to solve this using the experimental feature passPerPreset, so in the mean time I’ve switched on the no-parameter-properties tslint rule.

I can confirm with a local test in my project:

Input:

class C extends Object {
  constructor(public x) {
    super();
  }
}

Output with just typescript plugin:

class C extends Object {
  constructor(x) {
    super();
    this.x = x;
  }

}

Including the classes transform:

{
  "presets": [
    "@babel/typescript"
  ],
  "plugins": [
    "@babel/plugin-transform-classes"
  ],
}

Will output:

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

function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

let C =
/*#__PURE__*/
function (_Object) {
  _inherits(C, _Object);

  function C(x) {
    _classCallCheck(this, C);

    return _possibleConstructorReturn(this, (C.__proto__ || Object.getPrototypeOf(C)).call(this));
  }

  return C;
}(Object);

Using just plugins and changing the order doesn’t seem to result in a different output:

{
  "plugins": [
    "@babel/plugin-transform-typescript",
    "@babel/plugin-transform-classes"
  ],

Seems like “passPerPreset” fixes it for me.

{
	"passPerPreset": true,
	"presets": [
		["@babel/preset-env", { "modules": false }]
	],
	"plugins": [
		"@babel/plugin-transform-typescript"
	]
}

I understand what it’s doing, however, running tsc won’t give any errors, since it’s completely valid typescript. There is a mismatch between what the TS compiler outputs as JS, and what babel outputs as JS. This results in broken code, without babel or tsc complaining about it.

I could understand reasons for not supporting this feature, but in that case I feel it should throw an error and list this as a unsupported TS feature in the readme.