Confusión de TypeScript React.FC <Props>

Resuelto Kuldeep Bora asked hace 4 años • 5 respuestas

Estoy aprendiendo TypeScript y algunas partes me resultan confusas. Un bit está debajo:

interface Props {
  name: string;
}

const PrintName: React.FC<Props> = (props) => {
  return (
    <div>
      <p style={{ fontWeight: props.priority ? "bold" : "normal" }}>
        {props.name}
      </p>
    </div>
  )
}

const PrintName2 = (props: Props) => {
  return (
    <div>
      <p style={{ fontWeight: props.priority ? "bold" : "normal" }}>
        {props.name}
      </p>
    </div>
  )
}

Para los dos componentes funcionales anteriores, veo que TypeScript genera el mismo código JS. El PrintName2componente me parece más simplificado en cuanto a legibilidad. Me pregunto cuál es la diferencia entre las dos definiciones y si alguien está usando el segundo tipo de componente React.

Kuldeep Bora avatar Jan 30 '20 21:01 Kuldeep Bora
Aceptado

Gracias por todas las respuestas. Son correctos pero estaba buscando una versión más detallada. Investigué un poco más y encontré esto en React+TypeScript Cheatsheets en GitHub.

Componentes de funciones
Estos pueden escribirse como funciones normales que toman un argumento de accesorios y devuelven un elemento JSX.

type AppProps = { message: string }; /* could also use interface */

const App = ({ message }: AppProps) => <div>{message}</div>;

Qué pasa React.FC/ React.FunctionComponent? También puedes escribir componentes con React.FunctionComponent(o la abreviatura React.FC):

const App: React.FC<{ message: string }> = ({ message }) => (
  <div>{message}</div>
);

Algunas diferencias con la versión "función normal":

Proporciona verificación de tipo y autocompletar para propiedades estáticas como displayName, propTypesy defaultProps. Sin embargo, actualmente existen problemas conocidos al usar defaultPropscon React.FunctionComponent. Consulte este número para obtener más detalles; desplácese hacia abajo hasta nuestra defaultPropssección para obtener recomendaciones de escritura allí.

Proporciona una definición implícita de hijos (ver más abajo); sin embargo, hay algunos problemas con el tipo de hijos implícitos (por ejemplo, DefinitelyTyped#33006), y de todos modos podría considerarse un mejor estilo ser explícito acerca de los componentes que consumen hijos.

const Title: React.FunctionComponent<{ title: string }> = ({
  children,
  title
}) => <div title={title}>{children}</div>;

En el futuro, puede marcar automáticamente los accesorios como de solo lectura, aunque eso es un punto discutible si el objeto de accesorios está desestructurado en la lista de parámetros.

React.FunctionComponentes explícito sobre el tipo de retorno, mientras que la versión de la función normal es implícita (o necesita anotaciones adicionales).

En la mayoría de los casos, hay muy poca diferencia qué sintaxis se utiliza, pero la React.FCsintaxis es un poco más detallada sin proporcionar una ventaja clara, por lo que se le dio prioridad a la sintaxis de "función normal".

Kuldeep Bora avatar Jan 30 '2020 17:01 Kuldeep Bora

React.FCNo es la forma preferible de escribir un componente de React, aquí hay un enlace .

Yo personalmente uso este tipo:

const Component1 = ({ prop1, prop2 }): JSX.Element => { /*...*/ }

Breve lista de React.FCdesventajas:

  1. Proporciona una definición implícita de hijos, incluso si su componente no necesita tener hijos. Eso podría causar un error.
  2. No admite genéricos.
  3. No funciona correctamente con defaultProps.
Alexander Kim avatar May 01 '2020 16:05 Alexander Kim

Mejor solución:

El segundo enfoque + un tipo de retorno

const PrintName2 = ({ prop1, prop2 }: Props): JSX.Element => { /** */}

Esto te da control total sobre los accesorios y es más explícito (no hay magia oculta).

Enlace a GitHub PR para eliminar React.FC

Kent C Dodds tiene algunas ideas sobre por qué esto está aquí

Solución subóptima:

La primera versión (React.FC) agregará algunos tipos: provienen de React Typings

interface FunctionComponent<P = {}> {
  (props: PropsWithChildren<P>, context?: any): ReactElement | null;
  propTypes?: WeakValidationMap<P>;
  contextTypes?: ValidationMap<any>;
  defaultProps?: Partial<P>;
  displayName?: string;
}

Este enfoque es útil por varias razones, pero una obvia es que si su componente tiene hijos, entonces no necesita agregar manualmente un childrenaccesorio. No es genial porque hay problemas con los accesorios predeterminados y muchos componentes no tienen hijos.

Jonathan Irwin avatar Jan 30 '2020 14:01 Jonathan Irwin

Dado que está utilizando React y TypeScript, siempre debe usar el primer patrón, ya que garantizará que su componente tenga un tipo más estricto, ya que implica que será PrintNamedel tipo React Functional Component y requiere accesorios de tipo Props.

const PrintName: React.FC<Props>

Puede leer la definición completa de la interfaz para componentes funcionales en el repositorio de mecanografía de React TypeScript .

El segundo ejemplo que proporcionó no proporciona ningún tipo de tipificación, excepto que es una función que toma un conjunto de parámetros de tipo Propsy que puede devolver cualquier cosa en general.

Por lo tanto, escribir

const PrintName2 = (props:Props)

es similar a

const PrintName2: JSX.Element = (props:Props) 

ya que TypeScript definitivamente no puede inferir automáticamente que es un componente funcional.

wentjun avatar Jan 30 '2020 15:01 wentjun