web-dev-qa-db-fra.com

réagir-router-dom avec TypeScript

J'essaye d'employer le routeur de réaction avec TypeScript. Cependant, j'ai des problèmes avec la fonction withRouter. Sur la dernière ligne, je reçois une erreur assez étrange:

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 '{}’

Le code ressemble à:

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);
34
Haris Bašić

J'utilise une approche différente pour résoudre ce problème. Je sépare toujours les différentes propriétés (routeur, standard et dispatch), je définis donc les interfaces suivantes pour mon composant:

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
}

Vous pouvez maintenant créer un nouveau type combinant toutes les propriétés dans un seul type, mais je combine toujours les types lors de la définition du composant (je n'ajoute pas l'état ici, mais si vous en avez besoin, continuez). La définition du composant ressemble à ceci:

class Home extends React.Component<HomeProps & HomeDispatchProps> {
  constructor(props: HomeProps & HomeDispatchProps) {
    super(props);
  }

  public render() {
    return (<span>{this.props.match.params.title}</span>);
  }
}

Nous devons maintenant connecter le composant à l'état via un conteneur. Cela ressemble à ceci:

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);

Cette méthode permet une connexion entièrement typée. Le composant et le conteneur sont donc entièrement typés et leur refactorisation peut être effectuée en toute sécurité. La seule chose qui ne soit pas sûre pour le refactoring est le paramètre de la route mappé sur l'interface HomeRouterProps.

30
Ramon de Klein

Je pense que c'est un problème de compilation de types TypScript, mais j'ai trouvé une solution de contournement:

interface HomeProps extends RouteComponentProps<any>, React.Props<any> {
}
14
carlosvin

Ceci est un problème de typages TypeScript. Puisque withRouter () fournira les accessoires de routage dont vous avez besoin au moment de l'exécution, vous voulez dire aux clients qu'ils doivent uniquement spécifier les accessoires other. Dans ce cas, vous pouvez simplement utiliser un ComponentClass brut:

export default withRouter(connectModule) as React.ComponentClass<{}>;

Ou, si vous souhaitiez transmettre des accessoires (définis dans une interface appelée OwnProps), vous pouvez le faire:

export default withRouter(connectModule) as React.ComponentClass<OwnProps>;

Il y a un peu plus de discussion ici

6
Taylor Lafrinere

Il semble que vous ayez le bon usage d'appliquer les accessoires de correspondance, d'historique et d'emplacement à votre composant. Je voudrais vérifier dans votre répertoire node_modules pour voir quelles versions de react-router et react-router-dom vous avez, ainsi que les modules @types.

J'ai essentiellement le même code que vous et le mien travaille avec les versions suivantes:

{
  "@types/react-router-dom": "^4.0.4",
  "react-router-dom": "^4.1.1",
}
2
Peter Benavides

Après avoir parcouru les définitions TypeScript, j’ai découvert l’interface RouteComponentProps et modélise maintenant mes conteneurs de la manière suivante: 

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>{} 

maintenant, dans la classe de composant, les accessoires de route peuvent être accédés comme suit: let teamid = this.props.match.params.teamId; 

0
SimperT

+1 pour la réponse de Ramon. Vous pouvez absolument obtenir une couverture type complète ici. Pour ajouter un peu - j'ai ajouté l'appel à withRouter.

interface FooProps extends RouteComponentProps<Foo> {
  foo: string;
}

const Foo = ({ history, foo }: FooProps) => <span/>;

const RoutedFoo = withRouter(Foo);

mes dépendances:

"@types/react-router-dom": "^4.3.0",
"TypeScript": "^2.9.2",
0
dmwong2268