primers
React Advanced React API Introduction and Basic Practice Since I use Ts to implement the example in the React Advanced blog, I encountered Ts error when implementing the cloneElement API example.
The following error message is displayed:
No overload matches this call.
The last overload gave the following error.
Argument of type 'ReactNode' is not assignable to parameter of type 'ReactElement<any, string | JSXElementConstructor<any>>'.
Type 'undefined' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'.
Copy the code
CloneElement: ReactElement; ReactElement: ReactElement; ReactElement: ReactElement; ReactElement: ReactElement;
This situation got me thinking, what is the relationship between ReactNode and ReactElement?
ReactNode, ReactElement
Looking at the declaration file, we can conclude that the ReactNode type is as follows:
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
Copy the code
We found that ReactNode is a union type, and the types include ReactChild, ReactFragment, ReactPortal, Boolean, NULL, and undefined.
Among the union types of ReactNode, ReactChild is also a union type. The type is ReactElement or ReactText.
The fact that ReactElement is nothing more than a subtype of ReactNode is obvious.
Let’s take a look at ReactElement:
interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
type: T;
props: P;
key: Key | null;
}
Copy the code
This is an interface that has properties such as Type, props, and key.
JSX.Element
Jsx. Element is obtained by executing React. CreateElement or by translating JSX.
const jsx = <div>hello</div>
const ele = React.createElement("div".null."hello");
<p> // <- ReactElement = JSX.Element
<Custom> // <- ReactElement = JSX.Element
{true && "test"} // <- ReactNode
</Custom>
</p>
Copy the code
Element is a ReactElement whose props and type generics are set to any. Jsx. Element exists because different libraries implement JSX differently, that is, JSX is a global namespace. React is set up in different libraries as follows:
declare global {
namespace JSX {
interface Element extends React.ReactElement<any, any> { }
}
}
Copy the code
summary
From the above analysis, we can conclude that ReactElement is a subset of ReactNodes. In React jsX. Element and ReactElement are almost equivalent. The way to implement jsx. Element in React is ReactElement.
To solve the problem
The cause of this problem becomes clear after we identify ReactNode and ReactElement.
In the figure below, the children type is ReactNode, and the cloneElement method accepts the children type as a ReactElement.
So we need to set the children type to be a ReactElement.
As shown in the figure above, we can restrict the type of children to ReactElement by generics.
This way, if we write code without paying attention to the children type and mistakenly provide a children of ReactText, Ts will check for the error.
You see, the benefits of Ts are quite a lot.
reference
- when-to-use-jsx-element-vs-reactnode-vs-reactelement
- #cloneElement #cloneElement