类型'HTMLElement |的参数“ null”不可分配给“ Element”类型的参数类型'null'不能分配给类型'Element'.ts2345

问题描述

我有index.html

<body>
    <div id="portal"></div>
    <div id="root"></div>
</body>

,并希望在portal div之外的root div中使用以下组件,

import React from 'react';

const portalDiv = document.getElementById('portal');

function Portal1(props) {
  return ReactDOM.createPortal(
    <div>
      {props.children}
    <div/>,portalDiv); //here
}

export default Portal1;

但是我遇到此错误类型'HTMLElement |的参数。 “ null”不可分配给“ Element”类型的参数。 VScode中的类型'null'不能分配给类型'Element'.ts(2345)

我正在使用Typescript。请帮忙。

解决方法

其他人已经回答您应该添加一个null检查,但是Typescript还具有一个非null断言,当您确定通过添加{ {1}}运算符,直到语句结尾:

!
,

所以我不知道是否有人仍然遇到这个问题,但有一个更简单直接的解决方案。 只需使用 "as" 关键字声明模态元素
const modalRoot = document.getElementById("modal-root") as HTMLElement; 这消除了错误。 我建议查看这个很棒的 react-typescript 备忘单。
https://github.com/typescript-cheatsheets/react

,

getElementById可以返回null,但是createPortal不接受null

如果 知道 该门户网站div将存在,则使代码明确相关:

const portalDiv = document.getElementById('portal');
if (!portalDiv) {
    throw new Error("The element #portal wasn't found");
}

这将使TypeScript缩小常量的类型,而删除该类型的| null部分。如果有人更改了某些内容,例如当该代码再次运行时div不存在,它还会给您一个很好的主动警告。

,

由于getElementById可能返回null。因此,您只需在使用like之前先检查一下即可:

function Portal1({ children }) {
  return portalDiv ? ReactDOM.createPortal(<>{children}</>,portalDiv) : null;
}
,

我认为最好的解决方案不是使其成为 nullHTMLDIVElement 而是在用例 尝试让 typescript 知道 DivElement 此刻可能是空的,但你会只需使用“!”就可以承担责任符号。

以下代码示例:

import React,{useEffect} from 'react';
import ReactDOM from 'react-dom';
import './modal-portlet.style.scss';

const modalRoot = document.getElementById('modalRoot');

type Props = {
  children: JSX.Element;
};
const ModalPortlet: React.FC<Props> = ({children}): JSX.Element => {
  const divContainer = window.document.createElement('div');
  divContainer.setAttribute('class','modal-container');

  useEffect(() => {
    /**********
     * immediately the component mount append @divContainer as the childNode of @modalRoot in the DOM
     **********/
    modalRoot!.appendChild(divContainer);

    return () => {
      modalRoot!.removeChild(divContainer);
    };
  });

  /************
   * return the createPortal api that takes the children(JSX) and inject it into @divContainer which is already a childNode of @modalRoot
   ************/
  return <>{ReactDOM.createPortal(children,divContainer)}</>;
};

export default ModalPortlet;