web-dev-qa-db-fra.com

Valeur de propriété par défaut dans le composant React à l'aide de TypeScript

Je n'arrive pas à comprendre comment définir les valeurs de propriété par défaut de mes composants à l'aide de TypeScript.

C'est le code source:

class PageState
{
}

export class PageProps
{
    foo: string = "bar";
}

export class PageComponent extends React.Component<PageProps, PageState>
{
    public render(): JSX.Element
    {
        return (
            <span>Hello, world</span>
        );
    }
}

Et quand j'essaye d'utiliser le composant comme ceci:

ReactDOM.render(<PageComponent />, document.getElementById("page"));

Je reçois une erreur en disant que la propriété foo est manquante. Je veux utiliser la valeur par défaut. J'ai également essayé d'utiliser static defaultProps = ... dans le composant, mais cela n'a eu aucun effet, comme je le pensais.

src/TypeScript/main.tsx(8,17): error TS2324: Property 'foo' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<PageComponent> & PageProps & { children?: ReactEle...'.

Comment utiliser les valeurs de propriété par défaut? De nombreux composants JS que mon entreprise utilise dépendent d'eux et ne pas les utiliser n'est pas un choix.

92
Tom

Accessoires par défaut avec composant de classe

Utiliser static defaultProps est correct. Vous devriez également utiliser des interfaces, pas des classes, pour les accessoires et l'état. 

Mise à jour 2018/12/1: TypeScript a amélioré la vérification de type liée à defaultProps au fil du temps. Lisez-le pour en savoir plus sur l'utilisation la plus récente jusqu'aux utilisations et problèmes plus anciens. _

Pour TypeScript 3.0 et supérieur

TypeScript spécifiquement ajout de la prise en charge de defaultProps pour que la vérification de type fonctionne comme prévu. Exemple:

interface PageProps {
  foo: string;
  bar: string;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, { this.props.foo.toUpperCase() }</span>
        );
    }
}

Ce qui peut être rendu et compilé sans passer un attribut foo:

<PageComponent bar={ "hello" } />

Notez que:

  • foo est pas marqué comme facultatif (c.-à-d. foo?: string) même s'il n'est pas requis en tant qu'attribut JSX. Marquer comme optionnel signifierait qu'il pourrait s'agir de undefined, mais en réalité il ne sera jamais undefined car defaultProps fournit une valeur par défaut. Pensez-y de la même manière que vous pouvez marquer un paramètre de fonction comme facultatif ou avec une valeur par défaut, mais pas les deux, mais les deux signifient que l'appel n'a pas besoin de spécifier une valeur . TypeScript 3.0+ traite defaultProps de la même manière, ce qui est vraiment bien pour les utilisateurs de React!
  • La defaultProps n'a pas d'annotation de type explicite. Son type est déduit et utilisé par le compilateur pour déterminer quels attributs JSX sont requis. Vous pouvez utiliser defaultProps: Pick<PageProps, "foo"> pour vous assurer que defaultProps correspond à un sous-ensemble de PageProps. Plus sur cette mise en garde est expliqué ici .
  • Cela nécessite @types/react version 16.4.11 pour fonctionner correctement.

Pour TypeScript 2.1 à 3.0

Avant TypeScript 3.0 implémenté la prise en charge du compilateur pour defaultProps, vous pouviez toujours vous en servir, et cela fonctionnait à 100% avec React au moment de l’exécution, mais TypeScript ne prenant en compte que les accessoires lors de la vérification des attributs JSX, vous devez marquer les accessoires avec des valeurs par défaut facultatives. ?. Exemple:

interface PageProps {
    foo?: string;
    bar: number;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps: Partial<PageProps> = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, world</span>
        );
    }
}

Notez que:

  • Il est judicieux d'annoter defaultProps avec Partial<> pour qu'il vérifie le type de vos accessoires, mais vous n'êtes pas obligé de fournir toutes les propriétés requises avec une valeur par défaut, ce qui n'a aucun sens, car les propriétés requises ne devraient jamais nécessiter de valeur par défaut.
  • Lorsque vous utilisez strictNullChecks, la valeur de this.props.foo sera possibly undefined et nécessitera une assertion non nulle (c'est-à-dire this.props.foo!) ou un garde du type (c'est-à-dire if (this.props.foo) ...) pour supprimer undefined. Ceci est gênant puisque la valeur prop par défaut signifie qu’elle ne sera jamais indéfinie, mais TS n’a pas compris ce flux. C'est l'une des principales raisons pour lesquelles TS 3.0 a ajouté un support explicite pour defaultProps.

Avant TypeScript 2.1

Cela fonctionne de la même manière, mais vous n'avez pas de types Partial. Il vous suffit donc d'omettre Partial<> et de fournir des valeurs par défaut pour toutes les propriétés requises (même si ces valeurs par défaut ne seront jamais utilisées) ou d'omettre complètement l'annotation de type explicite.

Accessoires par défaut avec Composants fonctionnels

Vous pouvez également utiliser defaultProps sur des composants de fonction, mais vous devez taper votre fonction sur l'interface StatelessComponent (FunctionComponent dans @types/react version 16.7.2 +) afin que TypeScript connaisse l'existence de defaultProps sur la fonction:

interface PageProps {
  foo?: string;
  bar: number;
}

const PageComponent: StatelessComponent<PageProps> = (props) => {
  return (
    <span>Hello, {props.foo}, {props.bar}</span>
  );
};

PageComponent.defaultProps = {
  foo: "default"
};

Notez qu'il n'est pas nécessaire d'utiliser Partial<PageProps> n'importe où, car StatelessComponent.defaultProps est déjà spécifié comme partiel dans TS 2.1+.

Une autre alternative intéressante (c’est ce que j’utilise) consiste à déstructurer vos paramètres props et à attribuer directement les valeurs par défaut:

const PageComponent: StatelessComponent<PageProps> = ({foo = "default", bar}) => {
  return (
    <span>Hello, {foo}, {bar}</span>
  );
};

Alors vous n’avez pas besoin de la defaultProps du tout! Sachez que si vous do fournissez defaultProps sur un composant de la fonction, il sera prioritaire sur les valeurs de paramètre par défaut, car React transmettra toujours explicitement les valeurs defaultProps (les paramètres ne sont jamais indéfinis; utilisé.) Vous utiliseriez donc l’un ou l’autre, pas les deux.

213
Aaron

Avec TypeScript 2.1+, utilisez Partial <T> au lieu de rendre les propriétés de votre interface facultatives.

export interface Props {
    obj: Model,
    a: boolean
    b: boolean
}

public static defaultProps: Partial<Props> = {
    a: true
};
16
Learner

Avec TypeScript 3.0, il existe une nouvelle solution à ce problème:

export interface Props {
    name: string;
}

export class Greet extends React.Component<Props> {
    render() {
        const { name } = this.props;
        return <div>Hello ${name.toUpperCase()}!</div>;
    }
    static defaultProps = { name: "world"};
}

// Type-checks! No type assertions needed!
let el = <Greet />

Notez que pour que cela fonctionne, vous avez besoin d’une version plus récente de @types/react que 16.4.6. Cela fonctionne avec 16.4.11.

5
CorayThan

D'après un commentaire de @pamelus sur la réponse acceptée:

Vous devez soit rendre toutes les propriétés d'interface facultatives (mauvaises) ou spécifiez également la valeur par défaut pour tous les champs obligatoires (inutile boilerplate) ou évitez de spécifier le type sur defaultProps.

En fait, vous pouvez utiliser l'héritage d'interface de TypeScript . Le code résultant est seulement un peu plus détaillé.

interface OptionalGoogleAdsProps {
    format?: string;
    className?: string;
    style?: any;
    scriptSrc?: string
}

interface GoogleAdsProps extends OptionalGoogleAdsProps {
    client: string;
    slot: string;
}


/**
 * Inspired by https://github.com/wonism/react-google-ads/blob/master/src/google-ads.js
 */
export default class GoogleAds extends React.Component<GoogleAdsProps, void> {
    public static defaultProps: OptionalGoogleAdsProps = {
        format: "auto",
        style: { display: 'block' },
        scriptSrc: "//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"
    };
3
Harald Mühlhoff

Pour ceux qui ont des accessoires optionnels qui nécessitent des valeurs par défaut. Crédit ici :)

interface Props {
  firstName: string;
  lastName?: string;
}

interface DefaultProps {
  lastName: string;
}

type PropsWithDefaults = Props & DefaultProps;

export class User extends React.Component<Props> {
  public static defaultProps: DefaultProps = {
    lastName: 'None',
  }

  public render () {
    const { firstName, lastName } = this.props as PropsWithDefaults;

    return (
      <div>{firstName} {lastName}</div>
    )
  }
}
0
Morlo Mbakop