Posted at

React Router with TypeScriptでちゃんと型をつける

react-routerでRouteコンポーネントを使って<Route path='foo' component={Bar}/>のように書くと、Barコンポーネントにはmatch,location,historyの3つのpropsが渡されます。

これらのpropsをどう型定義するかという話です。


Routing

例えば以下のようなroutingがあるとします。


app.tsx

  <BrowserRouter>

<Switch>
<Route path="/counter" component={Counter} />
</Switch>
</BrowserRouter>

Counterコンポーネントにはmatch, location, historyのpropsが渡されます。


RouteComponentProps

Routeのcomponentに指定したコンポーネントのpropsはreact-router-domのRouteComponentPropsをextendする形で使えばうまく型定義できます。


counter.tsx

import { RouteComponentProps } from 'react-router-dom'

interface Props extends RouteComponentProps<{}> {
 // 他の型定義
}

const Counter = (props: Props) => (
<div>
<Navi history={props.history} />
</div>
)


RouteComponentPropsの型定義:


index.d.ts

import * as React from 'react';

import * as H from 'history';

export interface RouteComponentProps<Params extends { [K in keyof Params]?: string } = {}, C extends StaticContext = StaticContext, S = H.LocationState> {
history: H.History;
location: H.Location<S>;
match: match<Params> | null;
staticContext?: C;
}


paramsが必要なときはRouteComponentProps<{id: string}>という感じで渡してあげれば良いです。


History

さらにCounterがNaviという子コンポーネントを持っており、historyだけ渡している場合にNaviではどう型を定義するかというと、RouteComponentProps型定義でも使われているhistoryを使えば良いです。


navi.tsx


import * as H from 'history'
interface Props {
history: H.History
}

const Navi = (props: Props) => (<div><button onClick={props.history.push('/next')}/><div/>)


locationの場合は、H.LocationでOK。

以上です。