15

I am using react and mobx-state-tree and I use @inject to inject the stores into my component. So in the end I access the store via this.props.uiStore inside of my component.

Unfortunately Visual Studio Code can't infer the type of my store, so I don't have any code completion for the properties. I wondered if I could use jsDoc for that (since it works for methods quite well), but couldn't find a way. I was thinking of something along the lines of:

export default class DeviceMirror extends React.Component {
  /**
   * @namespace
   * @property {object}  props
   * @property {UiStore}  props.uiStore
   */
  props

But it does not work.

adiga
  • 34,372
  • 9
  • 61
  • 83
stoefln
  • 14,498
  • 18
  • 79
  • 138

3 Answers3

9

You can use JSDoc to make Visual Studio Code properly infer React components props, the trick is the use of @extends {Component<{type def for props}, {type def for state}>}}:

file: store.js (this is just an example file to demonstrate how the intellinsense will catch definitions but any object, class, typedefiniton, and probably even json would do. If you can import it and reflect it, you can link it to a Component props)

    class CustomClass {
        // ...
    }
    // Note: exporting an object would also do
    export default class UiStore {
        /**
         * @type {string} this is a string
         */
        str = null
        /**
         * @type {number} this is a number
         */
        num = null
        /**
         * @type {Date} this is a Date
         */
        dat = Date
        /**
         * @type {CustomClass} this is a CustomClass
         */
        cls = null
    }

file: test.jsx

    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    import UiStore from './store';

    /**
     * @typedef Props
     * @prop {UiStore} uiStore
     */

    /**
     * @extends {Component<Props, {}>}}
     */
    export default class DeviceMirror extends Component {
        static propTypes = {
            // not needed for intellisense but prop validation does not hurt
            uiStore: PropTypes.instanceOf(UiStore),
        }
        /**
         * @param {Props} props - needed only when you don't write this.props....
         */
        constructor(props) {
            super(props);
            this.s = props.uiStore.str;
        }
        render() {
            const { uiStore } = this.props;
            return <p>{uiStore.str}</p>;
        }
    }

VSCode can use this kind of declarations and will offer intellisense and code completion. both from inside and outside the component file:

screenshot of vscode

remix23
  • 2,632
  • 2
  • 11
  • 21
  • Thats great to know! However, I need to redefine all properties (which I have defined already in MST format), right? – stoefln Mar 11 '19 at 11:16
  • No you don't have to redefine anything as long as code completion on the desired type is already possible outside the React component. This is just a matter of correctly assigning the generic types of the parameterized class Component (or PureComponent) `with @extends {Component<{}, {}>}`. You can even use an object instance as the type definition. – remix23 Mar 11 '19 at 11:23
  • Note that you can skip State definition with an empty object `{}` as a placeholder. – remix23 Mar 11 '19 at 11:28
3

There's no way to go from a TypeScript type declaration to a mobx-state-tree model definition. However, if you write the mobx-state-tree model definition, then you can generate the TypeScript type from it; Using a MST type. So you would have to convert your existing interfaces, but at least you wouldn't have to keep maintaining two copies of the same information.

import { types, Instance } from 'mobx-state-tree';

const uiStore = types.model({
  prop: types.string,
});
export type IuiStore = Instance<typeof uiStore>;

export default uiStore;
victor zadorozhnyy
  • 889
  • 1
  • 12
  • 25
  • Can you elaborate on this? How would I use `IuiStore` in my component to get code completion? – stoefln Mar 10 '19 at 11:10
  • `IuiStore ` could be a type oк interface and the way to use is just to assign your props to a new variable inside the component like `let myProps: uiType = this.props.uiStore`. I personally prefer to use decorators in my index file and keep a component as a pure function so it's easy to test it and it's not tie-up with any state management libs. – victor zadorozhnyy Mar 11 '19 at 06:14
0

For those of you who also work with MST stores, here is how you get code completion in visual studio code:

import DbStore from '../stores/DbStore'
import UiStore from '../stores/UiStore'    

/**
 * @typedef Props
 * @prop { typeof UiStore.Type } uiStore
 * @prop { typeof DbStore.Type } dbStore
 * @prop { boolean } editMode
 * @prop { Array } history
 * ....
 */
/**
 * @extends {React.Component<Props, {}>}}
 */
@inject('dbStore')
@inject('uiStore')
@observer
class TestView extends React.Component { ....
stoefln
  • 14,498
  • 18
  • 79
  • 138