JSX.Element, ReactNode, ReactElement: When to Use What in TypeScript?

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

JSX.Element vs ReactNode vs ReactElement: The Type Battle You Must Win



Hello, colleague! If you write React with TypeScript, you've probably encountered a situation where the compiler starts complaining about return types. "Expected JSX.Element, got ReactNode" — a familiar error? Or maybe you've seen ReactElement in generics and wondered: "What's the difference anyway?"



Spoiler: these are not just academic terms. Choosing the right type can speed up your code, prevent bugs, and make components more predictable. Today we'll break down this topic with real examples so you never confuse these three types again. Let's go!



Quick Primer: What is What



Let's start with the basics. All three types are parts of the same ecosystem, but with different levels of abstraction.



ReactElement

This is the basic building block. ReactElement is an object with a type, props, and a key. It represents a "blueprint" of an element that React will later turn into a real DOM node. If you write React.createElement('div', null, 'Hello'), you get exactly a ReactElement.



import React from 'react';

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


Important: ReactElement is a generic. You can specify the props type and the element type:



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


JSX.Element

This is an extension of ReactElement that adds JSX specificity. Essentially, JSX.Element is ReactElement<any, any>. When you write <div /> in JSX, TypeScript sees exactly JSX.Element.



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


The main difference from ReactElement is that JSX.Element is not parameterized. It's simply "any JSX element".



ReactNode

Now this is the broadest type. ReactNode includes:

  • ReactElement
  • Strings
  • Numbers
  • Booleans (true/false)
  • null and undefined
  • Arrays of the above
  • React Portal


In simple terms: ReactNode is everything that React can render. This is the type used for children in components.



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


When to Use What? Practical Scenarios



Now for the interesting part — let's figure out which type to choose in real situations.



Scenario 1: Component Return Value

Your component returns JSX. Which type should you specify?



// ❌ Bad: too general a typefunction MyComponent(): ReactNode {  return <div>Hello</div>;}

// ✅ Good: use JSX.Elementfunction MyComponent(): JSX.Element { return <div>Hello</div>;}

// ✅ Excellent: if strict props typing is neededfunction MyComponent(): React.ReactElement<{ title: string }> { return <div>Hello</div>;}


Why? A component always returns JSX (or null if it renders nothing). ReactNode is too broad — it allows returning a string, number, or array, which can lead to unexpected errors.



Scenario 2: children in a Component

Here ReactNode is your best friend. Child elements can be anything: a string, another component, null (conditional rendering), or an array.



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

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

Blogs

Book Recommendations