JSX.Element, ReactNode, ReactElement: ¿cuándo usar qué en TypeScript?

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

JSX.Element vs ReactNode vs ReactElement: La batalla de tipos que debes ganar



¡Hola, colega! Si escribes en React con TypeScript, seguramente te has encontrado con una situación en la que el compilador empieza a quejarse de los tipos de valores devueltos. "Expected JSX.Element, got ReactNode" — ¿una error familiar? ¿O quizás has visto ReactElement en genéricos y te has preguntado: "¿Cuál es la diferencia?"



Spoiler: no son solo términos académicos. Elegir el tipo correcto puede acelerar tu código, prevenir errores y hacer que los componentes sean más predecibles. Hoy analizaremos este tema con ejemplos reales para que nunca más confundas estos tres tipos. ¡Vamos allá!



Breve introducción: qué es qué



Empecemos con lo básico. Los tres tipos son partes de un mismo ecosistema, pero con diferentes niveles de abstracción.



ReactElement

Este es el bloque de construcción básico. ReactElement es un objeto con tipo, props y clave. Representa un "plano" del elemento que React luego convertirá en un nodo DOM real. Si escribes React.createElement('div', null, 'Hello'), obtienes exactamente un ReactElement.



import React from 'react';

const element: React.ReactElement = React.createElement('div', { className: 'box' }, '¡Hola!');// Tipo: ReactElement<{ className: string }, 'div'>


Importante: ReactElement es un genérico. Puedes especificar el tipo de props y el tipo de elemento:



type MyElement = React.ReactElement<{ name: string }, 'button'>;


JSX.Element

Esta es una extensión de ReactElement que añade la especificidad de JSX. Básicamente, JSX.Element es ReactElement<any, any>. Cuando escribes <div /> en JSX, TypeScript ve exactamente JSX.Element.



const jsxElement: JSX.Element = <div>JSX.Element</div>;


La principal diferencia con ReactElement es que JSX.Element no se parametriza. Es simplemente "cualquier elemento JSX".



ReactNode

Y este es el tipo más amplio. ReactNode incluye:

  • ReactElement
  • Cadenas de texto
  • Números
  • Booleanos (true/false)
  • null y undefined
  • Arrays de lo anterior
  • React Portal


En palabras simples: ReactNode es todo lo que React puede renderizar. Este es el tipo que se usa para children en los componentes.



type ReactNode =   | React.ReactElement  | string  | number  | boolean  | null  | undefined  | React.ReactNode[];


¿Cuándo usar qué? Escenarios prácticos



Ahora viene lo interesante: analicemos qué tipo elegir en situaciones reales.



Escenario 1: Valor de retorno del componente

Tu componente devuelve JSX. ¿Qué tipo especificar?



// ❌ Mal: tipo demasiado generalfunction MyComponent(): ReactNode {  return <div>Hola</div>;}

// ✅ Bien: usamos JSX.Elementfunction MyComponent(): JSX.Element { return <div>Hola</div>;}

// ✅ Excelente: si se necesita tipado estricto de propsfunction MyComponent(): React.ReactElement<{ title: string }> { return <div>Hola</div>;}


¿Por qué? El componente siempre devuelve JSX (o null, si no renderiza nada). ReactNode es demasiado amplio: permite devolver una cadena, un número o un array, lo que puede provocar errores inesperados.



Escenario 2: children en el componente

Aquí ReactNode es tu mejor amigo. Los elementos hijos pueden ser cualquier cosa: una cadena, otro componente, null (renderizado condicional) o un array.



interface CardProps {  title: string;  children: React.ReactNode; // ✅ Correcto}

function Card({ title, children }: CardProps): J

Blogs

Book Recommendations