createPortal - 当 JavaScript 运行正常时,TypeScript document.getElementById 类型问题?

Con*_*han 4 javascript typescript reactjs

我正在尝试使用 ReactDOM.createPortal,但 VSCode 中没有突出显示“ReactDOM”或“文档”,当将鼠标悬停在“document.getElementById('overlay-root')”上时,我收到此错误:

Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element'.
  Type 'null' is not assignable to type 'Element'.
Run Code Online (Sandbox Code Playgroud)

这是代码:

import styles from './CartModal.module.css';
import ReactDOM from 'react-dom';
import Card from '../UI/Card/Card';

interface CartModalProps {
  onClose?: () => void
}

const DisplayCartModal: React.FC<CartModalProps> = (props) => {

  return ReactDOM.createPortal(
    <>
      <CartModal />
    </>, 
    document.getElementById('overlay-root')
  )
}

export default DisplayCartModal;
Run Code Online (Sandbox Code Playgroud)

我尝试将文件扩展名切换为 .js 以查看这是否是 TypeScript 错误,事实上,当我更改它(并删除了 TS 特定语法)时,所有内容都突出显示并且运行良好。它没有返回 null,而是返回了正确的 HTML 元素。非常感谢帮助!

Mal*_*lio 10

问题是,document.getElementById('overlay-root') 可能为空。你(我假设)知道它不会,但 Typescript 不知道。

您可以用感叹号断言非空性,如下所示:

ReactDOM.createPortal(
<>
  <CartModal />
</>, 
document.getElementById('overlay-root')!
)
Run Code Online (Sandbox Code Playgroud)

如果你的断言是假的,你会得到一个运行时错误,这是一件非常糟糕的事情。


Rya*_* Le 5

在打字稿中,createPortal接收类型的容器Element

export function createPortal(children: ReactNode, container: Element, key?: null | string): ReactPortal;
Run Code Online (Sandbox Code Playgroud)

同时,document.querySelector返回一个 Element OR Null

querySelector<E extends Element = Element>(selectors: string): E | null;
Run Code Online (Sandbox Code Playgroud)

这是两者不匹配的情况,要解决此问题,您需要将返回对象转换为querySelector

document.querySelector('#overlay-root') as Element,
Run Code Online (Sandbox Code Playgroud)

但为了捕获任何错误,您应该在使用它之前检查 null,这样您就不必进行强制转换:

const DisplayCartModal: React.FC<CartModalProps> = (props) => {
  const overlayRootEl = document.querySelector('#overlay-root');

  return overlayRootEl
    ? ReactDOM.createPortal(
      <>
        <CartModal />
      </>,
      overlayRootEl,
    )
    : null;
};
Run Code Online (Sandbox Code Playgroud)