Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mobx Flow functions are not type checked by FlowType without .bind(this)

When we use MobX flow decorated functions, flowtype thinks this is of type any and does no type checking.

class MyComponent extends Component<*> {
   actionMethod = flow(function*(){
        yield this.notAMethod();
   });
}

However, if we bind this to the generator, flow understands the type of this is MyComponent.

 class MyComponent extends Component<*> {
       actionMethod = flow((function*(){
            yield this.notAMethod();
       }).bind(this));
    }

My question is how can we ensure that these methods are type checked.

  • Is there any linting rule to ensure we bind(this) correctly?
  • Can we improve the mobx typings?
  • Is this an issue with flow?
like image 262
Adam Mills Avatar asked Oct 09 '18 09:10

Adam Mills


People also ask

What is the use of flow wrapper in mobx?

The flow wrapper is an optional alternative to async / await that makes it easier to work with MobX actions. flow takes a generator function as its only input. Inside the generator, you can chain promises by yielding them (instead of await somePromise you write yield somePromise ).

How do I handle asynchronous processes in mobx?

See subclassing for more information. In essence, asynchronous processes don't need any special treatment in MobX, as all reactions will update automatically regardless of the moment in time they are caused. And since observable objects are mutable, it is generally safe to keep references to them for the duration of an action.

When to mark a method as an action in mobx?

To leverage the transactional nature of MobX as much as possible, actions should be passed as far outward as possible. It is good to mark a class method as an action if it modifies the state. It is even better to mark event handlers as actions, as it is the outer-most transaction that counts.

What is the action annotation in mobx?

The action annotation should only be used on functions that intend to modify the state. Functions that derive information (performing lookups or filtering data) should not be marked as actions, to allow MobX to track their invocations. action annotated members will be non-enumerable. // Intermediate states will not become visible to observers.


1 Answers

Your question reduces to the ability to create a custom lint. Eslint has a great library for writing your own eslint rules. You can compare using https://astexplorer.net/, the difference between your code with and without this. Then you could write an eslint rule that looks something like this (Untested):

// @no-flow
"use strict";
// Help from  https://astexplorer.net/
module.exports.rules = {
  "mobx-flow-requires-bind": context => ({
    CallExpression: function(node) {
      const ancestors = context.getAncestors();
      const parent = ancestors.length > 0 && ancestors[ancestors.length - 1];
      if (node.callee && node.callee.name === "flow") {
        if (node.arguments.length === 1) {
          const callee = node.arguments[0].callee;
          if (!(callee && callee.property && callee.property.name === "bind")) {
            context.report(node, "Calls to flow must be used with .bind");
          }
        }
      }
    }
  })
};

You can integrate the above code into your repo with this tutorial.

like image 126
Nicholas Pipitone Avatar answered Sep 30 '22 06:09

Nicholas Pipitone