我应该使用什么类型的 TypeScript 来引用道具中的匹配对象?

在我的 React 容器/组件中,我可以使用哪种类型来引用 React 路由器 DOM 包含的 match部分?

interface Props {
match: any // <= What could I use here instead of any?
}


export class ProductContainer extends React.Component<Props> {
// ...
}
79607 次浏览

You don't need to add it explicitly. You can use RouteComponentProps<P> from @types/react-router as a base interface of your props instead. P is type of your match params.

import { RouteComponentProps } from 'react-router';


// example route
<Route path="/products/:name" component={ProductContainer} />


interface MatchParams {
name: string;
}


interface Props extends RouteComponentProps<MatchParams> {
}
// from typings
import * as H from "history";


export interface RouteComponentProps<P> {
match: match<P>;
location: H.Location;
history: H.History;
staticContext?: any;
}


export interface match<P> {
params: P;
isExact: boolean;
path: string;
url: string;
}

To add onto @Nazar554's answer above, the RouteComponentProps type should be imported from react-router-dom, and implemented as follows.

import {BrowserRouter as Router, Route, RouteComponentProps } from 'react-router-dom';


interface MatchParams {
name: string;
}


interface MatchProps extends RouteComponentProps<MatchParams> {
}

Further, to allow for re-usable components, the render() function allows you to pass only what the component needs, rather than the entire RouteComponentProps.

<Route path="/products/:name" render={( {match}: MatchProps) => (
<ProductContainer name={match.params.name} /> )} />


// Now Product container takes a `string`, rather than a `MatchProps`
// This allows us to use ProductContainer elsewhere, in a non-router setting!
const ProductContainer = ( {name}: string ) => {
return (<h1>Product Container Named: {name}</h1>)
}

The problem was that even after creating an interface for the match<Params> the type warning was still there. Here is the code which worked for me:

interface MatchParams {
firstParam: string;
optionalParam?: string;
}


export const CreditPortfolioDetail: FC<RouteComponentProps<MatchParams>> = (props) => {
const { firstParam, optionalParam} = props.match.params;
// ...
}

Simple solution

import { RouteComponentProps } from "react-router-dom";


const Container = ({ match }: RouteComponentProps<{ showId?: string}>) => {
const { showId } = match.params?.showId;//in case you need to take params
}

This is a complete example I tested.

DemoComponent.tsx

// Created by BaiJiFeiLong@gmail.com at 2021/9/25 20:15


import React from "react";
import {RouteComponentProps} from "react-router"


export default class DemoComponent extends React.Component<{
prop1: string,
prop2: string,
prop3: string
} & RouteComponentProps<{
param1: string,
param2: string,
param3: string
}>, {
state1: string,
state2: string,
state3: string
}> {


static defaultProps = {
prop1: "PROP1",
prop2: "PROP2",
prop3: "PROP3"
}


constructor(props: any) {
super(props);
this.state = {
state1: "STATE1",
state2: "STATE2",
state3: "STATE3"
}
}




render() {
return <ul>
<li>prop1 = {this.props.prop1}</li>
<li>prop2 = {this.props.prop2}</li>
<li>prop3 = {this.props.prop3}</li>
<li>state1 = {this.state.state1}</li>
<li>state2 = {this.state.state2}</li>
<li>state3 = {this.state.state3}</li>
<li>param1 = {this.props.match.params.param1}</li>
<li>param2 = {this.props.match.params.param2}</li>
<li>param3 = {this.props.match.params.param3}</li>
</ul>
}
}

The route

<Route exact path="/demo/:param1/:param2/:param3" component={DemoComponent}/>

The call

/demo/foo/bar/baz

The result

prop1 = PROP1
prop2 = PROP2
prop3 = PROP3
state1 = STATE1
state2 = STATE2
state3 = STATE3
param1 = foo
param2 = bar
param3 = baz