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.
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 ).
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With