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

Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element'. Type 'null' is not assignable to type 'Element'.ts(2345)

我有index.html

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

并希望在 portal divroot 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' 类型的参数。 类型 'null' 不可分配给类型 'Element'.ts(2345) in VScode.

我正在使用 Typescript。

因为 getElementById 可能 returns 为空。所以你只需在使用之前简单地检查一下:

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

getElementById可以returnnull,但是createPortal不接受null.

如果您知道门户div将存在,请在代码中明确说明:

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

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

其他人回答说您应该添加一个 null-check,但是 Typescript 也有一个 non-null 断言,当您 确定 通过在语句末尾添加 ! 运算符,该值永远不会为空:

const portalDiv = document.getElementById('#your-element')!;

我认为最好的解决方案是不要将其设为 null HTMLDIVElement 而是在 用例 中尝试让打字稿知道 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;

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

我也遇到了同样的错误,所以我尝试了几种不同的方法,但对我有用的方法是处理空条件 即 const portalDiv = document.getElementById('portal')!;

当我们 select DOM 树中的 HTMLElement 使用 getElementById 时,它 return 是文档中与指定的 select 或匹配的元素,如果找不到匹配项,则基本上 return 为 null。

让我们获取门户元素:

let portalDiv = document.getElementById("portal");

如果门户存在于 DOM 树中,它将 return HTMLElemnt 如果找不到它 returns null

所以 getElementById 的 return 类型是 HTMLElement | null,因为 ReactDom.createPrortal(children: ReactNode, element: HTMLElement, id: string) 的第二个参数是严格的 HTMLElement 我们必须将我们的 portalDivHTMLElement 以消除警告。

因为我们确定 portalDiv 确实存在,所以我们可以使用此方法来处理 null 条件。

let portalDiv = getElementById("portal") as HTMLElement;

现在我们可以使用 portalDiv 而不会出现任何错误:

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