Skip to content

Map class property assertion fails when using babel-plugin-transform-runtime #177

Description

@jedwards1211

Issuehunt badges

This is a:

  • Bug Report
  • Feature Request
  • Question
  • Other

Which concerns:

  • flow-runtime
  • babel-plugin-flow-runtime
  • flow-runtime-validators
  • flow-runtime-mobx
  • flow-config-parser
  • The documentation website

What is the current behaviour?

Code

// @flow
// @flow-runtime assert, annotate

class Foo {
  bar: Map<string, any> = new Map()

  getValue(name: string) {
    return this.bar.get(name)
  }
}

new Foo().getValue('hello')

.babelrc

{
  "presets": [["env", {"targets": {"node": "current"}}], "flow"],
  "plugins": [
    "transform-decorators-legacy",
    ["flow-runtime", {"annotate": false, "assert": false}],
    "transform-runtime",
    "transform-class-properties",
  ],
}

Erroneous error

/Users/andy/iron-pi-webapp/node_modules/flow-runtime/dist/flow-runtime.js:9331
        throw error;
        ^

RuntimeTypeError: Default value for property Foo.bar must be an instance of Map

Expected: Map

Actual: Map

Transpiled code and explanation

babel-plugin-transform-runtime converts usage of Map to _map2.default, where _map2 is:

var _map = require('babel-runtime/core-js/map');

var _map2 = _interopRequireDefault(_map);

But babel-plugin-flow-runtime decorates the class property with a runtime reference to 'Map', which resolves to something else (depending on the environment).

'use strict';

var _defineProperty = require('babel-runtime/core-js/object/define-property');

var _defineProperty2 = _interopRequireDefault(_defineProperty);

var _map = require('babel-runtime/core-js/map');

var _map2 = _interopRequireDefault(_map);

var _dec, _dec2, _class, _desc, _value, _class2, _descriptor;

var _flowRuntime = require('flow-runtime');

var _flowRuntime2 = _interopRequireDefault(_flowRuntime);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _initDefineProp(target, property, descriptor, context) {
  if (!descriptor) return;
  (0, _defineProperty2.default)(target, property, {
    enumerable: descriptor.enumerable,
    configurable: descriptor.configurable,
    writable: descriptor.writable,
    value: descriptor.initializer ? descriptor.initializer.call(context) : void 0
  });
}

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 _initializerWarningHelper(descriptor, context) {
  throw new Error('Decorating class property failed. Please ensure that transform-class-properties is enabled.');
}

// -runtime assert, annotate

let Foo = (_dec = _flowRuntime2.default.annotate(_flowRuntime2.default.class('Foo', _flowRuntime2.default.property('bar', _flowRuntime2.default.ref('Map', _flowRuntime2.default.string(), _flowRuntime2.default.any())), _flowRuntime2.default.method('getValue', _flowRuntime2.default.param('name', _flowRuntime2.default.string())))), _dec2 = _flowRuntime2.default.decorate(_flowRuntime2.default.ref('Map', _flowRuntime2.default.string(), _flowRuntime2.default.any())), _dec(_class = (_class2 = class Foo {
  constructor() {
    _initDefineProp(this, 'bar', _descriptor, this);
  }

  getValue(name) {
    let _nameType = _flowRuntime2.default.string();

    _flowRuntime2.default.param('name', _nameType).assert(name);

    return this.bar.get(name);
  }
}, (_descriptor = _applyDecoratedDescriptor(_class2.prototype, 'bar', [_dec2], {
  enumerable: true,
  initializer: function () {
    return new _map2.default();
  }
})), _class2)) || _class);


new Foo().getValue('hello');

What is the expected behaviour?


babel-plugin-flow-runtime should use functions to resolve names at runtime (e.g. _flowRuntime2.default.ref(() => Map, ...) instead of _flowRuntime2.default.ref('Map', ...), so that Babel's module transform doesn't break the reference to Map.

Which package versions are you using?

    "babel-core": "^6.26.0",
    "babel-plugin-flow-runtime": "^0.15.0",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-flow": "^6.23.0",

IssueHunt Summary

Backers (Total: $50.00)

Submitted pull Requests


Become a backer now!

Or submit a pull request to get the deposits!

Tips

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions