Skip to content

Typescript, react-redux and asyncComponent usage? #62

Open
@dawnmist

Description

@dawnmist

Hi,

I'm trying to use asyncComponent to load react-redux connected components for code splitting, but I'm having trouble with the asyncComponent Configuration's resolve typescript definitions. I'm not sure if I'm doing something wrong, or if there is an incompatibility between the return type of react-redux's connect and the resolve return type.

Very cut-down component setup example:
'./components/Page.tsx':

import * as React from 'react';

export interface PagePropsFromState {
  title: string;
}
export interface PagePropsFromDispatch {
  loadPage: (name: string, websocket: WebSocket) => void;
}
export interface PageOwnProps {
  websocket: WebSocket;
}
export type PageProps = PagePropsFromState & PagePropsFromDispatch & PageOwnProps;

interface PageState {
  counter: number;
}

export default class Page extends React.Component<PageProps, PageState> {
  constructor(props: PageProps) {
    super(props);
    this.state = {
      counter: 0
    };
  }

  onClick = () => {
    let counter = this.state.counter + 1;
    if (counter > 5) {
      this.props.loadPage('home', this.props.websocket);
      return;
    }
    this.setState({counter: counter});
  }

  render() : {
    return (
      <span onClick={this.onClick}>
        {this.props.title} clicks: {this.state.counter}
      </span>
    );
  }
}

'./containters/PageContainer.tsx:

import { bindActionCreator, Dispatch } from 'redux';
import { connect } from 'react-redux';
import { loadPage } from '../actions';
import { State } from '../reducers';
import Page, { PageOwnProps, PagePropsFromDispatch, PagePropsFromState } from '../components/Page';

const mapStateToProps = (state: State) => ({
  title: getTitle(state)
});

const mapDispatchToProps = (dispatch: Dispatch<State>) => bindActionCreator(loadPage, dispatch);

const PageContainer = connect<PagePropsFromState, PagePropsFromDispatch, PageOwnProps>(
  mapStateToProps,
  mapDispatchToProps
)(Page);

export default PageContainer;

'./App.tsx':

import * as React from 'react';
import { Store } from 'redux';
import { asyncComponent, AsyncComponentProvider } from 'react-async-component';
import ReconnectingWebSocket from 'reconnectingwebsocket';
import { State } from './reducers';
import HomePage from './containers/HomeContainer';

const AsyncPage = asyncComponent({
  name: 'Page',
  resolve: () => import(/* webpackChunkName: "page" */ './containers/PageContainer')
});

export interface AppProps {
  currentPage: string;
}
interface AppState {}

export default class App extends React.Component<AppProps, AppState> {
  ws: ReconnectingWebSocket;

  constructor(props: AppProps) {
    super(props);
    this.ws = new ReconnectingWebSocket(`${process.env.REACT_APP_SOCKET}`, ['my_app'], {
        reconnectInterval: 10000,
        maxReconnectInterval: 10000,
        reconnectDecay: 1.5
      });
  }

  render() {
    return (
      <AsyncComponentProvider>
        { currentPage === 'home' &&
          <HomePage websocket={this.ws} />
        }
        { currentPage === 'page' &&
          <AsyncPage websocket={this.ws} />
        }
      </AsyncComponentProvider>
    );
  }
}

Hopefully I haven't made any critical typos in the example.

What I am getting is Typescript is rejecting the AsyncPage's resolve function.
Message is:

Types of property 'resolve' are incompatible.
    Type '() => Promise<typeof "./containers/PageContainer">' is not assignable to type '() => Promise<ComponentType<{}>>'.
      Type 'Promise<typeof "./containers/PageContainer">' is not assignable to type 'Promise<ComponentType<{}>>'.
        Type 'typeof "./containers/PageContainer"' is not assignable to type 'ComponentType<{}>'.
          Type 'typeof "./containers/PageContainer"' is not assignable to type 'StatelessComponent<{}>'.
            Type 'typeof "./containers/PageContainer"' provides no match for the signature '(props: { children?: ReactNode; }, context?: any): ReactElement<any> | null'.

What do I need to provide by the way of type information to asyncComponent/Configuration to be able to use this with a connected component?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions