TypeScriptでリアクションルーターを使用しようとしています。ただし、withRouter関数を使用すると特定の問題が発生します。最後の行では、かなり奇妙なエラーが発生しています:
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 '{}’
コードは次のようになります。
import * as React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps, withRouter } from 'react-router-dom';
interface HomeProps extends RouteComponentProps<any> {
}
interface HomeState { }
class Home extends React.Component<HomeProps, HomeState> {
constructor(props: HomeProps) {
super(props);
}
public render(): JSX.Element {
return (<span>Home</span>);
}
}
const connectModule = connect(
(state) => ({
// Map state to props
}),
{
// Map dispatch to props
})(Home);
export default withRouter(connectModule);
別のアプローチを使用してこれを修正します。さまざまなプロパティ(ルーター、レギュラー、およびディスパッチ)を常に分離しているため、コンポーネントに次のインターフェイスを定義します。
interface HomeRouterProps {
title: string; // This one is coming from the router
}
interface HomeProps extends RouteComponentProps<HomeRouterProps> {
// Add your regular properties here
}
interface HomeDispatchProps {
// Add your dispatcher properties here
}
すべてのプロパティを単一の型に結合する新しい型を作成できるようになりましたが、コンポーネント定義中に常に型を結合します(ここでは状態を追加しませんが、必要な場合は先に進みます)。コンポーネント定義は次のようになります。
class Home extends React.Component<HomeProps & HomeDispatchProps> {
constructor(props: HomeProps & HomeDispatchProps) {
super(props);
}
public render() {
return (<span>{this.props.match.params.title}</span>);
}
}
ここで、コンテナを介してコンポーネントを状態に配線する必要があります。次のようになります。
function mapStateToProps(state, ownProps: HomeProps): HomeProps => {
// Map state to props (add the properties after the spread)
return { ...ownProps };
}
function mapDispatchToProps(dispatch): HomeDispatchProps {
// Map dispatch to props
return {};
}
export default connect(mapStateToProps, mapDispatchToProps)(Hello);
このメソッドは完全に型指定された接続を許可するため、コンポーネントとコンテナは完全に型指定され、リファクタリングしても安全です。リファクタリングに対して安全でない唯一のものは、HomeRouterProps
インターフェイスにマッピングされるルートのパラメーターです。
TypeScriptのタイピングコンパイルの問題だと思いますが、回避策を見つけました。
interface HomeProps extends RouteComponentProps<any>, React.Props<any> {
}
これはTypeScriptのタイピングの問題です。 withRouter()は実行時に必要なルーティングの小道具を提供するため、other小道具のみを指定する必要があることを消費者に伝えたいと思います。この場合、単純なComponentClassを使用できます。
export default withRouter(connectModule) as React.ComponentClass<{}>;
または、他のプロップ(OwnPropsと呼ばれるインターフェースで定義されている)を渡したい場合、これを行うことができます:
export default withRouter(connectModule) as React.ComponentClass<OwnProps>;
もう少し議論があります こちら
一致、履歴、および場所の小道具をコンポーネントに適用する適切な使用方法があるようです。 node_modules
ディレクトリをチェックして、react-router
とreact-router-dom
のバージョン、および@types
モジュールを確認します。
私はあなたと本質的に同じコードを持っています、そして私は次のバージョンで働いています:
{
"@types/react-router-dom": "^4.0.4",
"react-router-dom": "^4.1.1",
}
TypeScript定義を参照した後、RouteComponentProps
インターフェイスを発見したので、次のようにコンテナーをモデリングします。
type RouteParams = {
teamId: string; // must be type string since route params
}
interface Props extends RouteComponentProps<RouteParams>, React.Props<RouteParams> { }
type State = {
players: Array<Player>;
}
export class PlayersContainer extends React.Component<Props, State>{}
コンポーネントクラスでは、ルートプロップに次のようにアクセスできます:let teamid = this.props.match.params.teamId;
私がこれをやっている方法:
interface IOwnProps {
style?: CSSProperties;
}
interface INavProps {
item?: string;
}
type IProps = IOwnProps & RouteComponentProps<INavProps>;
export default class MapScreen extends PureComponent<IProps> {
...
}
ラモンの答えに+1。ここでは、完全なタイプカバレッジを絶対に取得できます。少し追加するには-withRouterへの呼び出しを追加しました。
interface FooProps extends RouteComponentProps<Foo> {
foo: string;
}
const Foo = ({ history, foo }: FooProps) => <span/>;
const RoutedFoo = withRouter(Foo);
私の依存関係:
"@types/react-router-dom": "^4.3.0",
"TypeScript": "^2.9.2",