paquet npm @types/react
nous permet d'utiliser React à l'intérieur de nos applications TypeScript. Nous définissons les composants comme
type Props = {...}
type State = {...}
export default class MyComponent extends React.Component<Props, State> {
}
ici, nous devons déclarer les types pour les accessoires et l'état des composants (dans les variables de type).
Après avoir déclaré ces types, TypeScript l'utilise pour valider l'utilisation de notre composant (la forme des accessoires qui lui sont passés).
Je veux créer un conteneur autour d'un tel composant. Le conteneur réutilisera les accessoires du composant. Mais pour créer un autre composant avec les mêmes accessoires, je dois redéclarer les types d'accessoires. Ou exportez-les à partir du fichier de composants d'origine et importez-les dans le conteneur:
// original file
export type Props = {...}
// container file
import MyComponent, { Props } from './original'
Mais j'importe déjà le MyComponent
de ce fichier. Ce composant contient déjà des informations sur les accessoires qu'il consomme (grâce aux variables de type dans React.Component
).
La question est comment puis-je accéder à ces informations à partir de la classe de composants elle-même sans exporter/importer explicitement le type d'accessoires?
Je veux quelque chose comme:
import MyComponent from './MyComponent'
type Props = MyComponent.Props // <= here access the component prop types
export default class MyContainer extends React.Component<Props, {}> {}
2019: remarqué que toutes les réponses ci-dessus sont assez obsolètes alors en voici une nouvelle.
Avec les versions TS plus récentes, vous pouvez utiliser des types de recherche.
type ViewProps = View['props']
Bien que très pratique, cela ne fonctionne qu'avec des composants de classe.
Les typographes React sont livrés avec un utilitaire pour extraire le type des accessoires de n'importe quel composant.
type ViewProps = React.ComponentProps<typeof View>
type InputProps = React.ComponentProps<'input'>
C'est un peu plus détaillé, mais contrairement à la solution de recherche de type:
Tout cela fait de cette solution la solution la plus évolutive: si vous décidez de migrer des classes vers les hooks, vous n'aurez pas besoin de refactoriser le code client.
À partir de TypeScript 2.8, vous pouvez utiliser des types conditionnels, par exemple donné:
interface MyComponentProps { bar: string; }
declare const MyComponent: React.Component<MyComponentProps>;
interface MyComponentClassProps { bar: string; }
declare const MyComponentClass: React.ComponentClass<MyComponentClassProps>;
interface MyStatelessComponentProps { bar: string; }
declare const MyStatelessComponent: React.StatelessComponent<MyStatelessComponentProps>;
Nous pouvons définir ces assistants:
type GetComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P> ? P : never
Et utilisez-les comme ceci:
// $ExpectType MyComponentProps
type MyComponentPropsExtracted = GetComponentProps<typeof MyComponent>
// $ExpectType MyComponentClassProps
type MyComponentClassPropsExtracted = GetComponentProps<typeof MyComponentClass>
// $ExpectType MyStatelessComponentProps
type MyStatelessComponentPropsExtracted = GetComponentProps<typeof MyStatelessComponent>
Mise à jour 2018-12-31: ceci est maintenant disponible dans les saisies officielles React via React.ComponentProps
.
Étant donné un composant React:
import React, { ComponentType, StatelessComponent } from 'react';
const MyComponent: StatelessComponent<{ foo: string }> = props => <div>{props.foo}</div>;
Tu peux faire:
const getProps = function<Props> (_MyComponent: ComponentType<Props>): Props {
return {} as Props;
};
const props = getProps(MyComponent);
// { foo: string; }
type MyComponentProps = typeof props;
Alternativement, vous pouvez augmenter les saisies React pour ajouter un assistant GetComponentProps
:
import React from 'react';
type NonNullable < T > = T & {};
declare module 'react' {
// Add helper for accessing props type of given component. Based off of
// https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182.
type GetComponentProps < C extends ComponentType < any > > = NonNullable<C['_doNotUse_props']>;
// We use interface merging to append properties to these types
interface StatelessComponent<P = {}> {
// eslint-disable-next-line camelcase
_doNotUse_props?: P;
}
interface ComponentClass<P = {}> {
// eslint-disable-next-line camelcase
_doNotUse_props?: P;
}
}
L'utilisation ressemble à ceci:
// { foo: string; }
type MyComponentProps = React.GetComponentProps<typeof MyComponent>;
J'ai initialement posté ceci dans https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182 .
Pour prendre un type de propriétés du composant
type Props = typeof MyComponent.defaultProps;
Vous pouvez vous demander pourquoi je prends typeof de defaultProps et non de propTypes. Pour expliquer cela, jetons un œil au fichier de définition
interface ComponentClass<P> {
new(props?: P, context?: any): Component<P, ComponentState>;
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
childContextTypes?: ValidationMap<any>;
defaultProps?: P;
displayName?: string;
}
Comme vous pouvez le voir, les propTypes sont enveloppés dans ValidationMap et il n'est pas facile d'obtenir des types bruts. Heureusement, defaultProps a des types bruts