Typescript: Les accessoires par défaut ne fonctionnent pas dans le composant fonctionnel

Créé le 4 mai 2019  ·  16Commentaires  ·  Source: microsoft/TypeScript

Version TypeScript: 3.4.5

Termes de recherche:
réagir default props defaultProps composant fonctionnel sans état

Code

import React from "react";

interface Props {
  name: string;
  optional: string;
}

const Component = ({ name, optional = "default" }: Props) => (
  <p>{name + " " + optional}</p>
);

const Test = () => <Component name="test" />;

Comportement prévisible:
Selon les notes de publication de TypeScript 3.0 , le prop optional ne devrait pas être requis dans Test car il a été défini avec une valeur par défaut à l'aide de la fonction d'initialisation par défaut ES2015 dans Component .

Comportement réel:
L'erreur de compilation suivante est générée:

La propriété 'facultative' est manquante dans le type '{nom: chaîne; } 'mais requis dans le type' Props '.

Lien Playground:
Lien
Il ne semble pas que le terrain de jeu prenne en charge TSX.

Problèmes liés:

27425

Question

Commentaire le plus utile

Avec TypeScript 3.1 ou supérieur, vous devriez être capable d'écrire:

export interface Props {
    name: string;
}

function Greet(props: Props) {
    return <div>Hello {props.name.toUpperCase()}!</div>;
}
Greet.defaultProps = {
  name: "world",
} as Partial<Props>; // Good practice, without it you could use a number as default prop and TypeScript wouldn't complain…

const component = <Greet />; // no errors

Tous les 16 commentaires

La documentation peut ne pas être claire à ce sujet, mais vous devez marquer la propriété comme facultative dans votre interface Props :

interface Props {
    name: string;
    optional?: string;
}

Cela ne semble pas correspondre à ce que disent les notes de publication:

export interface Props {
    name: string;
}

// ...

function Greet({ name = "world" }: Props) {
    return <div>Hello {name.toUpperCase()}!</div>;
}

Rendre le prop facultatif signifie également que lorsque vous accédez aux props en dehors du composant (dans un test), le système de types ne garantit pas que l'accessoire existe même si elle existera toujours.

Exemple:

const wrapper = shallow(<Test/>);

// optional is string | undefined instead of string
const optional = wrapper
        .find(Component)
        .props()
        .optional;

Si optional était une fonction, vous devriez vérifier qu'elle existe avant de l'exécuter. Un exemple est si vous fournissez un accessoire par défaut onClick qui appelle simplement preventDefault .

Avec TypeScript 3.1 ou supérieur, vous devriez être capable d'écrire:

export interface Props {
    name: string;
}

function Greet(props: Props) {
    return <div>Hello {props.name.toUpperCase()}!</div>;
}
Greet.defaultProps = {
  name: "world",
} as Partial<Props>; // Good practice, without it you could use a number as default prop and TypeScript wouldn't complain…

const component = <Greet />; // no errors

Est-ce un bogue que l'utilisation de la fonction d'initialisation par défaut ne fonctionne pas pour les accessoires par défaut? Cela semble être une régression étant donné que l'exemple donné dans les notes de publication ne fonctionne pas sur la dernière version de TypeScript.

@tbassetto Le problème avec cela est que TS ne vous oblige pas à fournir une valeur par défaut:

import React from 'react';

interface Props {
  myProp: string;
}

const Comp = (props: Props) => {
  return (
    <div>
      {props.myProp.toUpperCase()}
    </div>
  );
};

Comp.defaultProps = {

} as Pick<Props, 'myProp'>;

const comp = <Comp />;

L'autre chose ennuyeuse est le fait que vous devez le faire en premier lieu: si je tape Comp comme React.FC<Props> , alors defaultProps est bien tapé, mais d'autres problèmes surviennent .

Dans l'ensemble, le support TypeScripts JSX / React semble actuellement être dans un état étrange pas tout à fait parfait, mais fonctionne comme si tout allait bien (du moins à mes yeux - Principalement, je ne parviens pas à trouver de solide notes sur ce qui est actuellement la manière "officielle" de faire des composants React sans état d'une manière sûre de type pour 3.4.5).

Bien que je vois que tout le monde fait référence aux travaux, je ne parviens pas à faire fonctionner l'un d'entre eux.

Je suis sur la version 3.3.3

export interface Props {
  shouldTruncateContent: boolean;
}

const Alert: React.FunctionComponent<Props> = ({
  children,
  shouldTruncateContent = false
}) => {
  return (
        <S.Content shouldTruncateContent={shouldTruncateContent} size="fill">
          {children}
        </S.Content>
  );
};

Alert.defaultProps = {
  shouldTruncateContent: false
} as Pick<Props, 'shouldTruncateContent'>;

export default Alert;

Quelqu'un a-t-il une idée de la raison pour laquelle cela génère toujours l'erreur

TS2741: Property 'shouldTruncateContent' is missing in type '{ children: string; }' but required in type 'Props'.

J'ai essayé tous les correctifs proposés dans # 27425 et # 519 aussi.

@tomspeak Soit ma solution de contournement, soit celle de @Hotell (bien que celle-ci rende tous les accessoires optionnels). Testé sur 3.5 avec votre exemple de code.

Bien que je vois que tout le monde fait référence aux travaux, je ne parviens pas à faire fonctionner l'un d'entre eux.

Je suis sur la version 3.3.3

export interface Props {
  shouldTruncateContent: boolean;
}

const Alert: React.FunctionComponent<Props> = ({
  children,
  shouldTruncateContent = false
}) => {
  return (
        <S.Content shouldTruncateContent={shouldTruncateContent} size="fill">
          {children}
        </S.Content>
  );
};

Alert.defaultProps = {
  shouldTruncateContent: false
} as Pick<Props, 'shouldTruncateContent'>;

export default Alert;

Quelqu'un a-t-il une idée de la raison pour laquelle cela génère toujours l'erreur

TS2741: Property 'shouldTruncateContent' is missing in type '{ children: string; }' but required in type 'Props'.

J'ai essayé tous les correctifs proposés dans # 27425 et # 519 aussi.

Il vous suffit de créer shouldTruncateContent: boolean; facultatif shouldTruncateContent?: boolean;

La documentation peut ne pas être claire à ce sujet, mais vous devez marquer la propriété comme facultative dans votre interface Props :

interface Props {
    name: string;
    optional?: string;
}

J'utilise ce type facultatif partout. Pourquoi voter contre? Quelqu'un pourrait-il expliquer?

@ralexhassle , je ne peux pas expliquer les votes
Vous préférerez peut-être utiliser defaultProps , que l'exemple de la question n'utilise pas, mais en ce qui me concerne, marquer les propriétés optionnelles comme facultatives est probablement parfaitement bien ...

Le but du problème est que les accessoires ne sont pas facultatifs, mais ont une valeur par défaut (peuvent donc être éludés lors de l'utilisation du composant). Si vous marquez le prop comme facultatif avec ? alors TS suppose qu'il pourrait être indéfini et vous oblige à gérer ce cas. Cependant, il ne sera jamais indéfini car il existe une valeur par défaut. Les votes négatifs sont dus au fait que le commentateur n'a pas semblé comprendre le problème et a proposé quelque chose qui contredit les notes de version 3.0.

@RyanCavanaugh pourquoi le bot a-t-il fermé ce problème?

Peut-être que je l'ai manqué mais je ne vois pas de réponse réelle, malgré de nombreuses solutions de contournement?

PS: en utilisant TypeScript v4

Vous pouvez le faire de cette manière, ici les propriétés dans Props sont le paramètre facultatif et sont ensuite utilisées dans le composant.

interface Props {
  children: ReactNode;
  properties?: Record<string, unknown>;
}

const defaultProps: Props = {
  children: '',
  properties: {
    marginTop: 32,
    marginLeft: 0,
    marginBottom: 8,
    marginRight: 0,
  },
};

const RadioListLabel: React.FC<Props> = ({
  children,
  properties = defaultProps.properties,
}) => (
  <View
    margin={[
properties ? properties.marginTop : 0
        properties ? properties.marginLeft : 0
        properties ? properties.marginBottom : 0
        properties ? properties.marginRight : 0
      ]}
  >
    <Text size="m" variant="heading2" lineHeight="body">
      {children}
    </Text>
  </View>
  )

@lakhmeranikita Le but de ce problème est d'éviter de marquer un type d'accessoire comme facultatif.

Je n'ai pas pu obtenir les arguments par défaut de la fonction ou d'autres propositions pour taper correctement la vérification. La seule solution viable que j'ai pu trouver est la suivante:

import React from "react";

type DefaultProps = { optionalProp: number };
type Props = {
  requiredProp: "some_string" | "other_string";
} & DefaultProps;

export const BaseComponent = (props: Props) => {
  const { requiredProp, optionalProp } = props;
  return (
    <div>
      {requiredProp} {optionalProp}
    </div>
  );
};

BaseComponent.defaultProps = {
  optionalProp: 0,
} as Partial<DefaultProps>;

const comp = <BaseComponent requiredProp="some_string" />;

Cette page vous a été utile?
0 / 5 - 0 notes