0
votes

I have run into a TS2322 error while passing the method searchForBooks as props to SearchBooks component from the JumboBooks component:

JumboBooks.tsx (Parent)

import { RouteComponentProps } from 'react-router';
...
export class JumboBooks extends React.Component<RouteComponentProps<{}>, {}> {
...
searchForBooks(searchFilters: SearchParameters){...}    
...

 public render() {
        return (
            <div>
<SearchBooks searchForBooks={this.searchForBooks} />
...
}

SearchBooks.tsx

import { RouteComponentProps } from 'react-router';
...
interface IBookSearchProps {
    searchForBooks:(filters: SearchParameters)=> void; 
}

export class SearchBooks extends React.Component<IBookSearchProps & RouteComponentProps<{}>, {}> {
isearchForBooks() {
    var filters: SearchParameters = {
        // fill up parameters based on ref values
    };

    this.props.searchForBooks(filters);
  }
  ...
}

export interface SearchParameters
{
    ...
}

Error:

Error: TS2322: Type '{ searchForBooks: (searchFilters: SearchParameters) => void; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }>...'. Type '{ searchForBooks: (searchFilters: SearchParameters) => void; }' is not assignable to type 'Readonly>'. Property 'match' is missing in type '{ searchForBooks: (searchFilters: SearchParameters) => void; }'.

1
RouteComponentProps is adding a necessary match prop to your SearchBooks component, but it's not being provided. Does that come from a HOC later on? - Ross Allen
@RossAllen I have this import { RouteComponentProps } from 'react-router'; statement for both. - John
@John Right, but the type complaint is that when you're instantiating SearchBooks like this: <SearchBooks searchForBooks={this.searchForBooks} />, it's not getting the match prop that you said it needed when you did & RouteComponentProps<{}>. Where does that match prop come from? Is this component wrapped in a higher-order component? - Ross Allen
@RossAllen You've nailed it! Could you please let me know how to pass the match prop? As an answer to this question instead in this comment. - John
Which component are you using when you're rendering <Route component={...} />? Is that your JumboBooks component? - Ross Allen

1 Answers

3
votes

Only your JumboBooks is actually being using as a RouteComponent (being passed as <Route component={JumboBooks} />), so only it will automatically receive the match prop. Any descendants of JumboBooks that you want to have access to match you will have to pass in like a normal old prop:

export class JumboBooks extends React.Component<RouteComponentProps<{}>, {}> {
  public render() {
    return (
      <div>
        <SearchBooks
          match={this.props.match}
          searchForBooks={this.searchForBooks}
        />
      </div>
    );
  }
}

if you don't actually need the match prop, delete the RouteComponentProps<{}> from your SearchBooks component:

export class SearchBooks extends React.Component<IBookSearchProps, {}> {