Closed17

Next.jsでJSX.ElementとReactNodeの差異を考える

n13un13u

そもそもReactNodeとかReact Elementの話

https://ellreka.net/entry/reactelement_reactnode_reactfc_jsx

n13un13u

ReactPortal云々でエラーが出るのはReactNode型がReactPortalを含むUnionだから

n13un13u

@types/react@18.3.18 においては、JSX.ElementとReactElementはほぼ等価(あくまでもReact内部での話)

declare global {
    /**
     * @deprecated Use `React.JSX` instead of the global `JSX` namespace.
     */
    namespace JSX {
        // We don't just alias React.ElementType because React.ElementType
        // historically does more than we need it to.
        // E.g. it also contains .propTypes and so TS also verifies the declared
        // props type does match the declared .propTypes.
        // But if libraries declared their .propTypes but not props type,
        // or they mismatch, you won't be able to use the class component
        // as a JSX.ElementType.
        // We could fix this everywhere but we're ultimately not interested in
        // .propTypes assignability so we might as well drop it entirely here to
        //  reduce the work of the type-checker.
        // TODO: Check impact of making React.ElementType<P = any> = React.JSXElementConstructor<P>
        type ElementType = string | React.JSXElementConstructor<any>;
        interface Element extends React.ReactElement<any, any> {}
n13un13u

React.JSX.Elementは異なる

namespace JSX {
    type ElementType = GlobalJSXElementType;
    interface Element extends GlobalJSXElement {}
n13un13u

このGlobalJSXElementも結局はJSX.Element

// React.JSX needs to point to global.JSX to keep global module augmentations intact.
// But we can't access global.JSX so we need to create these aliases instead.
// Once the global JSX namespace will be removed we replace React.JSX with the contents of global.JSX
interface GlobalJSXElement extends JSX.Element {}
n13un13u

Why overriding

グローバルモジュールの拡張を維持するためにReact.JSX は global.JSX を指す必要があるが、global.JSX に直接アクセスできないため、代わりにエイリアスを作成し、将来的に global JSX の名前空間が削除された際には React.JSX を global.JSX の内容に置き換える予定である。

// React.JSX needs to point to global.JSX to keep global module augmentations intact.
// But we can't access global.JSX so we need to create these aliases instead.> // Once the global JSX namespace will be removed we replace React.JSX with the contents of global.JSX

n13un13u

const comp: React.FC = () => {}const comp = () : JSX.Element => {} の違い

n13un13u

FunctionComponentのdefinition

    interface FunctionComponent<P = {}> {
        (
            props: P,
            /**
             * @deprecated
             *
             * @see {@link https://legacy.reactjs.org/docs/legacy-context.html#referencing-context-in-lifecycle-methods React Docs}
             */
            deprecatedLegacyContext?: any,
        ): ReactNode;
}

要するに上記だけ

n13un13u

ReactNodeの定義を振り返る

n13un13u

@types/react@18.3.18の話

    type ReactNode =
        | ReactElement
        | string
        | number
        | Iterable<ReactNode>
        | ReactPortal
        | boolean
        | null
        | undefined
        | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[
            keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES
        ];
n13un13u

DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODESこれはrelease channelの差異で起きるReactNodeのunionに含めておきたい値を逃しておく場所

n13un13u

React.FCは戻り値に広めの方を使える、大きくうけて小さく出したいならJSX.Elementだけど正直そんな旨味なさそうだからReact.FCが良さそう

このスクラップは2025/02/19にクローズされました