15

I have the following piece of code (codesandbox):

import { ComponentType, ReactNode } from "react";

type DatetimeCell = ({ value }: { value: string }) => ReactNode;

function getDateTimeCell(): DatetimeCell {
  return ({ value }) => value;
}

function buildCell({
  value
}: {
  value: string;
}): ComponentType<{ value: string }> {
  const DateTimeCell = getDateTimeCell();
  return ({ value }) => <DateTimeCell value={value} />;
}

When returning in buildCell I get the error:

'DateTimeCell' cannot be used as a JSX component.
  Its return type 'ReactNode' is not a valid JSX element.

I thought ReactNode would be the most general type for valid JSX, but it seems like that is not the case.
Why is ReactNode not valid JSX and how can I solve this issue?

Edit: I know that wrapping value in React fragments solves the issue. However, in this specific application I need the type DatetimeCell to be able to return any valid JSX. So string should be included.

mgottsch
  • 559
  • 1
  • 3
  • 12

3 Answers3

9

Why is ReactNode not valid JSX ?? => https://stackoverflow.com/a/72353143/10146901

and how can I solve this issue? => Just Return JSX.Element as function return type.

function buildCell({ value }: { value: string }): JSX.Element { // ... my codes }

Solution of your codesandbox

Firoj Siddiki
  • 1,649
  • 1
  • 20
  • 22
  • I opened your solution and there still is an error in `buildCell`s return. – mgottsch Jul 22 '22 at 08:54
  • I think this is what you meant right? https://codesandbox.io/s/react-typescript-forked-sugr36 However, it still throws an error. – mgottsch Jul 23 '22 at 07:41
  • @mgottsch `'buildCell' is defined but never used` . This is just a basic warning **not an error**. Use the `buildCell` function somewhere, this warning will be gone – Firoj Siddiki Jul 24 '22 at 02:43
  • No, this is not what I mean. There is an error in the return function. 'DateTimeCell' cannot be used as a JSX component. Its return type 'ReactNode' is not a valid JSX element. Type 'undefined' is not assignable to type 'Element | null'.ts(2786) – mgottsch Jul 24 '22 at 08:31
0

Part of ReactNode type is undefined, which is not a valid JSX element I think.

The easiest way to solve the problem would be just to type DatetimeCell as Component as well, and always return an element from getDateTimeCell - just wrap the result in a fragment.

import React, { ComponentType } from 'react';

type DatetimeCell = ComponentType<{ value: string }>;

function getDateTimeCell(): DatetimeCell {
  return ({ value }) => <>{value}</>;
}

function buildCell({ value }: { value: string }): ComponentType<{ value: string }> {
  const DateTimeCell = getDateTimeCell();
  return ({ value }) => <DateTimeCell value={value} />;
}
  • 2
    I don't understand why `undefined` is not valid JSX. React does not crash when you use `undefined` as JSX, so why are the typings like this? (see here for proof: https://codesandbox.io/s/infallible-payne-yx4xes?file=/src/App.js). In my application, I need `DatetimeCell` to be able to return `string`, so I cannot use your solution (See edit). – mgottsch May 28 '22 at 08:36
  • I suspect `undefined` is not allowed just to stop people from forgetting to return something. – mpen Jan 09 '23 at 07:09
  • This is bad, because it prevents me from returning props.children since it can be undefined... – riv May 05 '23 at 19:43
-3

When you invoke DateTimeCell it expects a JSX element (ReactNode) to be returned. You are currently returning a string and not a React node in your getTimeCell function. I recommend typing your functional components using the FC type provided by react as below:

import { FC } from "react";

type Props = { value: string };
type DatetimeCell = FC<Props>;

function getDateTimeCell(): DatetimeCell {
  return ({ value }) => <>{value}</>;
}

function buildCell({ value }: Props): DatetimeCell {
  const DateTimeCell = getDateTimeCell();
  return ({ value }) => <DateTimeCell value={value} />;
}

buildCell({ value: "hello" });
Noah
  • 17
  • 1
  • 8
  • 1
    `string` is a `ReactNode` ```type ReactNode = ReactElement | string | number | ReactFragment | ReactPortal | boolean | null | undefined;``` (from `@types/react`) – mgottsch May 28 '22 at 08:41