gothinkster / react-mobx-realworld-example-app

Exemplary real world application built with React + MobX
https://react-mobx.realworld.io/
MIT License
1.25k stars 266 forks source link

Typescript typed issue on Stores : Type '{}' is not assignable to type 'Readonly<Props> #29

Closed abelkbil closed 6 years ago

abelkbil commented 6 years ago

Thanks for the repo.

I am confused on how to pass the props typed( React.Component <Props, State> ) for each components. Since I have defined the props of App, I get issue on index.tsx,

Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{ children?: ReactNode; }> & Reado...'.
  Type '{}' is not assignable to type 'Readonly<Props>'.
    Property 'commonStore' is missing in type '{}'.

Please help on this.

Index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import 'bootstrap/dist/css/bootstrap.css';
import './index.css';
import { Provider } from 'mobx-react';
import { useStrict } from 'mobx';
import { HashRouter } from 'react-router-dom';
import commonStore from './Stores/CommonStore';

// import ReconnectingWebsocket from 'reconnecting-websocket';

const stores = {
  commonStore
};

useStrict(true);

const root = (
  <Provider {...stores}>
    <HashRouter>
      <App />
    </HashRouter>
  </Provider>
);

ReactDOM.render(
  root,
  document.getElementById('root') as HTMLElement
);
registerServiceWorker();

App.tsx


import './App.css';
import * as React from 'react';
import Header from './Layouts/Utils/Header/Header';
import { observer, inject } from 'mobx-react';
import SingleDashboard from './Layouts/Pages/Dashboard/SingleDashboard/SingleDashboard';
import { withRouter } from 'react-router-dom';
import { commonStoreType } from './Stores/CommonStore';

interface Props {
  commonStore: commonStoreType;
}

interface State {

}

@inject('commonStore')
@withRouter
@observer
export default class App extends React.Component <Props, State> {
  constructor(props: Props) {
    super(props);
    // tslint:disable-next-line:no-console
    console.log(props);
  }

  componentWillMount() {
    if (!this.props.commonStore.token) {
      this.props.commonStore.setAppLoaded();
    }
  }

  render () {
    if (this.props.commonStore.appLoaded) {
      return (
        <div>
          <Header />
          <SingleDashboard />
        </div>
      );
    }
    return(
      <h1> Login </h1>
    );

  }
}

CommonStore


import { observable, action, reaction } from 'mobx';

class CommonStore  {

  @observable appName = 'Conduit';
  @observable token: string | null |undefined = window.localStorage.getItem('jwt');
  @observable appLoaded = false;

  constructor() {

  }

}

const commonStore = new CommonStore();
export type commonStoreType = typeof commonStore;
export default commonStore;
abelkbil commented 6 years ago

@andykog . Thanks . can you suggest what can be solution.

andykog commented 6 years ago

@abelkbil, you have to declare proptypes as optional, see the discussion: https://github.com/mobxjs/mobx-react/issues/256

abelkbil commented 6 years ago

@andykog Thanks for your support. I didn't use proptypes. And could you please mention where I have to make it optional.

andykog commented 6 years ago

@abelkbil, you may try in App.tsx:

interface Props {
-  commonStore: commonStoreType;
+  commonStore?: commonStoreType;
}
abelkbil commented 6 years ago

Thanks for support In typescript ,

interface Props {
    wid: string;
    // tslint:disable-next-line:no-any
    grid?: any;
    dashboardStore?: DashboardStore;
    widgetStore?: WidgetStore;
}
class Widget extends React.Component<Props, State> {

    dashboardStore?: DashboardStore;
    widgetStore?: WidgetStore;

    constructor(props: Props) {
        super(props);

        // this.dashboardStore = this.injected.dashboardStore;
        // this.widgetStore    = this.injected.widgetStore;

        this.dashboardStore = this.props.dashboardStore;
        this.widgetStore    = this.props.widgetStore;
        this.widget         = this.widgetStore.getWidget(this.props.wid) ;

This give a error image

What I do now Please comment it it the right solution.

interface InjectedProps extends Props {
    dashboardStore: DashboardStore;
    widgetStore: WidgetStore;
}
constructor(props: Props) {
    super(props);

    this.dashboardStore = this.injected.dashboardStore;
    this.widgetStore    = this.injected.widgetStore;
get injected() {
    return this.props as InjectedProps;
}

@andykog Thank you for consideration and time

andykog commented 6 years ago

@abelkbil, now widgetStore is optional, so typescript requires you to unwrap optional value somehow:

constructor(props: Props) {
    super(props);

-    this.dashboardStore = this.injected.dashboardStore;
-    this.widgetStore    = this.injected.widgetStore;
+    this.dashboardStore = this.injected.dashboardStore!;
+    this.widgetStore    = this.injected.widgetStore!;

or

    constructor(props: Props) {
        super(props);

        // this.dashboardStore = this.injected.dashboardStore;
        // this.widgetStore    = this.injected.widgetStore;

        this.dashboardStore = this.props.dashboardStore;
        this.widgetStore    = this.props.widgetStore;
-        this.widget         = this.widgetStore.getWidget(this.props.wid) ;
+        this.widget         = this.widgetStore!.getWidget(this.props.wid) ;
abelkbil commented 6 years ago

Okay. Got it. Very Thank You .