类型'HTMLElement |的参数“ null”不可分配给“ Element”类型的参数。类型'null'不能分配给类型'Element'.ts(2345)

时间:2020-08-21 10:00:41

标签: reactjs typescript react-dom

我有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。请帮忙。

5 个答案:

答案 0 :(得分:6)

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

!

答案 1 :(得分:5)

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

答案 2 :(得分:2)

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

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

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

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

我认为最好的解决方案不是使其成为 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;