111

In my React containers/component, which type could I use to reference the match part included by React Router DOM?

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

export class ProductContainer extends React.Component<Props> {
  // ...
}
Pek
  • 166
  • 1
  • 15
Nicolas Blanco
  • 11,164
  • 7
  • 38
  • 49

5 Answers5

189

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;
}
Nazar554
  • 4,105
  • 3
  • 27
  • 38
  • 3
    The problem with this is that Typescript then expects every use of that component to be actually passed in location history props etc. RouteComponentProps should have those props as optional. Have to wrap with Partial. – Glstunna Dec 17 '19 at 13:57
  • 1
    @Glstunna thanks for making me aware, how would that look like with partial? As well OP: please include your imports. – Toskan Feb 21 '20 at 08:10
  • TypeScript keeps asking me to pass the whole props set down to the component (`, I have the same code as seen above. – Leonardo Viada Mar 18 '21 at 22:43
  • 1
    @LeonardoViada Try passing the component using `` – Nazar554 Mar 19 '21 at 11:49
42

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>)
}
Craig Myles
  • 5,206
  • 3
  • 40
  • 37
The Aelfinn
  • 13,649
  • 2
  • 54
  • 45
9

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
}
dawid debinski
  • 392
  • 4
  • 6
1

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; 
    // ...
}
Lada
  • 21
  • 2
  • What is FC ? FC> – chrisl08 May 05 '21 at 07:13
  • It's React.FC, which is a type alias for React.FunctionComponent. Your function is actually a FunctionComponent, and by explicitly stating that, you also get the children property automatically added to your props (similar to how RouteComponentProps automatically adds location, match, etc.) – Mike Mansell May 12 '21 at 01:31
0

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
BaiJiFeiLong
  • 3,716
  • 1
  • 30
  • 28