loading...

Using React(Native) + MobX + Flow, Flow treats @inject as error

acro5piano profile image Kay Gosho ・2 min read

This is a story for flow, who doesn't understand ESNext Decorator.

Overview

Flow, who checks static type of JS(X), does not understand Decorator of ES Proposal (Stage 1, 2018/04/11).

At first, Flow does not pass if we use Decorators (like @inject).
We should add the following configuration to .flowconfig to execute flow check with Decorators.

esproposal.decorators=ignore

However, this let flow ignore Decorators so he does not interpret them.
Thus, he claims errors if we use @inject to inject MobX's store in React components.

To handle this error, the only one choice is not to use Decorators.

Another possible choice is to defaultProps as this article, suggests,

https://wietse.loves.engineering/using-flowtype-with-decorators-in-react-af4fe69e66d6

but I think we should avoid that kind of HACK because it increases undesirable types, and we cannot trust Props anymore.

Prerequisite

  • Developing with React(Native) + MobX + Flow
  • Installed babel-plugin-transform-decorators-legacy
  • Not select the easiest way using Component<*> or $flowFixMe

Problem

When @inject cause errors,

// App.jsx

// @flow

import { React, Component } from 'react'
import SomeComponent from './SomeComponent'
import Stores from './stores'

const stores = new Stores()

class App extends Component<{}> {
  render() {
    return (
      <Provider stores={stores}>
        <ScrollView>
          <SomeComponent someProperty="Hello" />
        </ScrollView>
      </Provider>
    )
  }
}
// SomeComponent.jsx

// @flow

import { React, Component } from 'react'
import SomeStore from './stores/SomeStore'

type Props = {
  someStore: SomeStore<*>;
  someProperty: string;
}

@inject('someStore')
@observer
export default class SomeComponent extends Component<Props> {
  render() {
    const { someProperty, someValue } = this.props.someStore

    return ( 
      <Text>{someProperty}, {someValue}</Text>
    )
  }
}

When we run flow check in our console, Flow creates the following error:

Property `someStore` is incompatible:

# ...

property `someStore`. Property not found in. see `SomeComponents.js`

# ...

props of React element `SomeComponent`

Let me describe how Flow feels.
He ignores Decorators so he doesn't understand Decorators.
Flow is nice guy, so he are focusing what he should do.

But we would like to use Decorators regardless to his policy.

Solution

Really simple, as if I don't have to write this article.

We should give up to use @inject until Flow supports it. Instead, we use inject as a normal JavaScript function.
I think this does not influent code readability.

// SomeComponent.js (part)

@observer
class SomeComponent extends Component<Props> {
  render() {
    const { someProperty, someValue } = this.props.someStore

    return ( 
      <Text>{someProperty}, {someValue}</Text>
    )
  }
}

export default inject('someStore')(SomeComponent)

Very simple solution, but for ES beginner it took much time to hit this solution.

Hope this article helps you.

Refs

https://gist.github.com/vonovak/29c972c6aa9efbb7d63a6853d021fba9

Posted on by:

Discussion

markdown guide