React: de PropTypes a TypeScript

Daniel Esteves

febrero 3, 2021

7 minutos de lectura

––– visitas

Si eres un desarrollador de React.js y no usas TypeScript, ¡este artículo es para ti!

🔌 Los Props son un medio de contacto

La característica central de React son los componentes. Nos ayuda a tener una verdadera separación de conceptos. Necesitamos muchos de ellos para construir una UI completa, así que tenemos que hacerlos interactuar.

La forma sencilla de mover datos de una componente a otro es a través de props:

single-post.jsx
import React from 'react'

import Post from './Post'

export default function SinglePost({ post }) {
  return (
    <>
      <Post title={post.title} description={post.description} />
    </>
  )
}

Es un patrón típico: un componente obtiene información de props, utiliza otros componentes y les proporciona props. El component SinglePost aquí utiliza el componente Post. Para proporcionar información desde SinglePost a Post, utilizamos props. Es un medio de comunicación, y debe ser visto como tal por los desarrolladores.

¿Qué es entonces un medio de contacto perfecto? No es tanto la capacidad de conectar, sino las características de UX que la rodean.

Para hablar con algunos amigos, utilizo WhatsApp. Puedo enviar y recibir mensajes, por supuesto, pero ¿cuáles son las características que tenemos alrededor de eso? Para saber si mi mensaje ha sido leído, he visto el check azul, genial. No tengo posibilidad de editar mi mensaje, no me gusta para nada (viva Telegram). ¿Qué pasa con los props de React? Puedes asignar un valor a un componente, vale, pero ¿qué experiencia de desarrollador tenemos alrededor de esto? Type check

Los types pueden fortalecer la DX (Developer Experience), ya que cuando algo está mal, puede alertarnos. El uso de prop-types es la forma normal de añadir type check a nuestros props.

post.jsx
import React from "react";
import PropTypes from "prop-types";

const Post = ({ title, description = "" }) => {
  return (
    <div className="px-6 py-2 rounded shadow-sm">
      <h2 className="text-2xl font-bold">{title}</h2>
      {description && (
        <p className="text-sm">{description}</p>
      )}
    </div>
  );
};

Post.propTypes = {
  title: PropTypes.string.isRequired,
  description: PropTypes.string
};

export default Post

Genial, podemos comunicarnos más eficientemente, ya que podemos decidir si una prop es requerida o no, si es una cadena u otro tipo, ¡o incluso dar una lista estricta de valores posibles! En nuestro caso, cuando queremos ver nuestro Post, y no le pasamos un título, esto es lo que nos dice el navegador:

Error de consola al no pasarle la prop title

¡Perfecto! Buena captura PropTypes, ¡gracias! Imagínate ahora que podemos tomar esta definición de los tipos de pruebas adicionales y la comprobación de todo nuestro código aún más allá 🚀

😎 TypeScript entra a la acción

La librería prop-types estaba incluida en React antes de React v15.5. El equipo de React tomó la opción de extraerla del core, fiel a su ideología de proporcionar una librería impopular, para permitir a los desarrolladores utilizar otros sistemas de tipado, como Flow o TypeScript. Esto último, vamos a probarlo.

Uno de los obstáculos de entrada de TypeScript es que la herramienta tiene que ser construida y configurada antes de que puedas usarla. No es tan fácil como yarn add prop-types, sin duda. En mi opinión, la mejor manera de aprender TypeScript es saltarse completamente este paso. Simplemente construye con CRA una nueva aplicación React, ¡y empecemos a aprender!

create-react-app.sh
yarn create react-app my-project --template typescript

Creado. Ahora, en nuestro componente de <Post />, vamos a cambiar de PropTypes a TypeScript.

post.tsx
import * as React from "react";

interface Props {
  title: string
  description?: string
}

const Post = ({ title, description = "" }: Props): JSX.Element => {
  return (
    <div className="px-6 py-2 rounded shadow-sm">
      <h2 className="text-2xl font-bold">{title}</h2>
      {description && (
        <p className="text-sm">{description}</p>
      )}
    </div>
  );
};

export default Post

La magia de TypeScript es que los type e interfaces que tenemos no sólo están disponibles exclusivamente. Para deducir el conocimiento, también analiza nuestro código.

TypeScript también viene con un pequeño extra: puede hacerlo justo en el editor de código cuando estás desarrollando. Para obtener pistas de una función, no tienes que esperar a que se ejecuten en el navegador, como ocurría con los prop-types.

Esto es lo que muestra mi VSCode con una función que tengo para verificar el tiempo de lectura de un texto:

Función de ejemplo para demostrar como TypeScript analiza el código

Ahora que estamos en esto, cambiemos también nuestro <SinglePost /> component:

single-post.tsx
import * as React from 'react'

import Post from './Post'

interface Props {
  post: {
    title: string
    description?: string
  }
}

export default function SinglePost({ post }: Props) {
  return (
    <>
      <Post title={post.title} description={post.description} />
    </>
  )
}

Pero, ¿qué pasa cuando queremos recibir un string que solo puede ser small, medium o large por ejemplo para el tamaño de la foto del post? Pues veamos el siguiente código y cómo actua TypeScript con la validación:

single-post.tsx
import * as React from 'react'

import Post from './Post'

interface Props {
  post: {
    title: string
    description?: string
    imageSize: "small" | "medium" | "large"
  }
}

export default function SinglePost({ post }: Props): JSX.Element {
  return (
    <>
      <Post title={post.title} description={post.description} />
    </>
  )
}
post.tsx
import * as React from 'react'

interface Props {
  title: string
  description?: string
  imageSize: 'small' | 'medium' | 'large'
}

const Post = ({ title, description = '', imageSize }: Props): JSX.Element => {
  return (
    <div className="px-6 py-2 rounded shadow-sm">
      <h2 className="text-2xl font-bold">{title}</h2>
      {description && <p className="text-sm">{description}</p>}
      <img src="https://picsum.photos/200/300" alt={title} className={imageSize} />
    </div>
  )
}

export default Post

Ahora si pasamos el mouse por encima de nuestro código donde está el componente <Post /> en single-post.tsx veremos el siguiente error:

Error de TypeScript de una prop faltante

Al agregar la nueva prop y abrir las comillas nos daremos cuenta que TypeScript ahora nos está autocompletando los size posibles que se le puede pasar y adicionalmente nos dice que debemos pasarle el prop correcto porque de otra forma no corresponde con los types que se declararon:

Error de TypeScript de la prop imageSize

Asombroso, ¿no lo crees? 😎

Y lo que es realmente genial es que TypeScript no está restringido a las partes props, a diferencia de PropTypes. Todo nuestro código JavaScript, incluso lo que no está conectado a nuestros componentes React, puede tener alertas. Incluso lo que no está totalmente conectado al front-end, ya que TypeScript funciona con NodeJS de mil maravillas.

Ahora, en nuestro código, podemos estar seguros.

TypeScript estará ahí para gritarnos si hay una discrepancia en algún lugar, señalando el fallo que estaba delante de nuestras narices, pero que de alguna manera pasamos por alto.

🧐 Conclusiones

No voy a mentir, el camino no es fácil con TypeScript y a veces la curva de aprendizaje puede ser dura. Pero sin duda vale la pena, supongo (?) 😂

Al proponer una herramienta de código abierto que es sensible a los avances de JavaScript, Microsoft ha hecho un gran trabajo. Este nuevo cuasi-estándar ha sido acogido por el ecosistema JS, y muchas librerías son compatibles con TypeScript para permitirnos hacer nuestro código, como hicimos en nuestros ejemplos con el JSX.Element de React.

Fue una apuesta a mi mismo poder entrar a TypeScript hace algún tiempo, y siempre perdía. ¿Ahora en 2021? Es una apuesta bastante obvia. Hoy, ¡úsalo! No te arrepentirás.

Oh y si me había olvidado comentarte JSX.Element es una forma de decirle a TypeScript que lo que retorna esa función es JSX y no necesita hacer nada más, en posteriores post que iré sacando sobre aprendiendo TypeScript con React explicaré para que sirve FunctionalComponent y JSX.Element en nuestro código.

- Los veo en el código 👨‍💻

¿Quieres ser el primero en leer mis posts?

Suscríbete al newsletter y tendrás tutoriales, noticias y posts de primera mano.

0 personas se han suscrito al newsletter

Persona programando animadas a través de un GIF

¿Tienes una idea?

Ponte en contacto a través de este botón para que pueda saber más de tu producto o servicio y podamos discutir la mejor manera de llevarlo a cabo.

Quiero plasmar mi idea