I'd like to have a variable that can be either a React component or a string, like this:
function MyComponent(): JSX.Element {
let icon: JSX.Element | string = "/example.png"; // (simplified)
return <div>{typeof icon === "JSX.Element" ? icon : <img src={icon} />}</div>;
}
however TS complains about my condition saying:
TS2367: This condition will always return 'false' since the types '"string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"' and '"JSX.Element"' have no overlap.
What should I do?
CodePudding user response:
The typeof
operator cannot return "JSX.Element"
. It can only return the string types listed in that error message:
"string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
Which means that you will need to check against something in that list, like "string"
.
function MyComponent(): JSX.Element {
let icon: JSX.Element | string = "/example.png";
return <div>{typeof icon === "string" ? <img src={icon} /> : icon }</div>;
}
CodePudding user response:
The accepted answer is the best for my simplified question.
If for some reason, you do want to type narrow against the element, rather than against string
, apparently you can also use React.isValidElement
, which type narrows.
You'd have to change the type JSX.Element
to ReactElement
:
function MyComponent(): JSX.Element {
let icon: ReactElement | string = "/example.png"; // (simplified)
return <div>{React.isValidElement(icon) ? icon : <img src={icon} />}</div>;
}
If changing to JSX.Element
is unacceptable, you could create your own user-defined type guard, which interrogates the object to determine if it is indeed a JSX.Element
(see here).