Redux + React Router + TypeScript環境 connectで生成したHOCでLink遷移ができない

# はじめに
Redux + React Router + TypeScriptの環境を構築していたところ
connectで生成されたコンポーネント内でReact RouterのLinkでうまく遷移ができななかったので、調べた解決方法を載せておきます。

# 環境
| 開発要素 | バージョン |
|---------|-----------|
| TypeScript | 2.4.1 |
| react | 15.6.1 |
| react-router-dom | 4.1.1 |
| redux | 3.7.2 |
| react-redux | 5.0.5 |

# 問題
React RouterのLinkコンポーネントを使用したリンクをクリックしても遷移しない(renderメソッドが実行されない)。

##### その他調べて分かったこと 
- reduxなし(Providerやconnectなし)の場合はリンクで遷移する
- Linkをクリック時は遷移しないが、そのあとに dispatch呼び出す動作をすると 遷移する



### ソース
問題が発生した時のソースコード（一部）

```ts:Root.tsx
import * as React from "react"
import { BrowserRouter } from "react-router-dom"
import { Provider } from "react-redux"
import App from "./App"

const store = // ... ストア生成

class Root extends React.Component<{}, {}> {
  public render() {
    return (
      <Provider store={store}>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </Provider >
    )
  }
}

export default Root
```      

```ts:App.tsx
import * as React from "react"
import { connect } from "react-redux"
import { Switch, Route, Link } from "react-router-dom"

interface Props extends React.Props<{}> {
  /* ... */
}

class App extends React.Component<Props, {}> {
  public render() {
    return (
      <Switch>
        // <Link />コンポーネントはChildA, ChildBの中で指定
        <Route exact={true} path="/" component={ChildA} />
        <Route path="/page2" component={ChildB} />
      </Switch>
    )
  }
}

/* RootStateはアプリのStateの型 */
const mapStateToProps = (rootState: RootState, onwProps: Props) => ({
  /* ... */
})

const mapPropsToDispatch = {
 /* ... */
}

export default connect(mapStateToProps, mapPropsToDispatch)(App)
```

RootコンポーネントではProvider, BrowserRootでAppコンポーネント(アプリケーションのメインコンポーネント) ラップして呼び出している。

## 対応1

[React Routerドキュメント](https://reacttraining.com/react-router/web/guides/redux-integration)によると、connectで生成されたコンポーネントの場合、Linkで遷移ができないことが記載されていた。
これの対応方法としてwithRouterメソッドでラップしなければならいよう。

```diff
--- import { Switch, Route, Link } from "react-router-dom"
+++ import { Switch, Route, Link, withRouter } from 'react-router-dom

--- export default connect(mapStateToProps, mapPropsToDispatch)(App)
+++ export default withRouter(connect(mapStateToProps, mapPropsToDispatch)(App))
```

# 別の問題が発生
上記のようにコードを修正したところ、今度はTypeScriptのビルドエラーが発生。

```
ERROR in [at-loader] ./src/pages/App.tsx:57:31
    TS2345: Argument of type 'ComponentClass<{}>' is not assignable to parameter of type 'StatelessComponent<RouteComponentProps<any>> | ComponentClass<RouteComponentProps<any>>'.
  Type 'ComponentClass<{}>' is not assignable to type 'ComponentClass<RouteComponentProps<any>>'.
    Type '{}' is not assignable to type 'RouteComponentProps<any>'.
      Property 'match' is missing in type '{}'.
```

## 対応2
withRouterの引数はコンポーネントのPropsにRouteComponentPropsを指定したコンポーネントである必要がある。
そこで、AppコンポーネントのPropsにRouteComponentPropsを継承した型を使用するよう修正した。

```diff

--- import { withRouter } from 'react-router-dom'
+++ import { withRouter, RouteComponentProps } from 'react-router-dom'

--- interface Props extends React.Props<{}> {
+++ interface Props extends RouteComponentProps<{}>, React.Props<{}> {

--- export default withRouter(connect(mapStateToProps, mapPropsToDispatch)(App))
+++ export default withRouter<{}>(connect(mapStateToProps, mapPropsToDispatch)(App))

```

以上で、Linkでの遷移ができるようになった。

# まとめ
 - コンポーネントのPropsにRouteComponentPropsのプロパティが必要
 - connectで生成されるコンポーネントの型に元コンポーネントのPropsを引き継ぐにはmapStateToPropsの第二引数に元コンポーネントのProps型を指定する

# 参考
 - [Redux Integration][link1]
 - [\[@types/react-router-dom\]: withRouter HoC produces compile error: "Property 'match' is missing in type '{}'." ][link2]

[link1]:https://reacttraining.com/react-router/web/guides/redux-integration
[link2]: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/17181