Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get code completion for typed react component properties?

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.

like image 534
stoefln Avatar asked Mar 01 '19 09:03

stoefln


2 Answers

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

like image 52
remix23 Avatar answered Sep 28 '22 08:09

remix23


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;
like image 29
victor zadorozhnyy Avatar answered Sep 28 '22 07:09

victor zadorozhnyy