I'm trying to use ReactDOM.createPortal and neither 'ReactDOM' or 'document' is highlighted in VSCode and I get this error when hovering over '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'.
Here's the code:
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;
I've tried switching the file extension to .js to see if this is a TypeScript error and indeed when I changed it (and removed TS-specific syntax) everything was highlighted and worked perfectly. It did not return null, it returned the correct HTML Element. Help is greatly appreciated!
I'm trying to use ReactDOM.createPortal and neither 'ReactDOM' or 'document' is highlighted in VSCode and I get this error when hovering over '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'.
Here's the code:
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;
I've tried switching the file extension to .js to see if this is a TypeScript error and indeed when I changed it (and removed TS-specific syntax) everything was highlighted and worked perfectly. It did not return null, it returned the correct HTML Element. Help is greatly appreciated!
Share Improve this question edited Sep 1, 2021 at 3:48 Ryan Le 8,4121 gold badge17 silver badges27 bronze badges asked Sep 1, 2021 at 3:28 Connor MooneyhanConnor Mooneyhan 5576 silver badges17 bronze badges2 Answers
Reset to default 10The issue is, document.getElementById('overlay-root')
might be null. You (I assume) know that it will not be, but Typescript does not know that.
You can assert that not-null-ness with an exclamation mark, like so:
ReactDOM.createPortal(
<>
<CartModal />
</>,
document.getElementById('overlay-root')!
)
If your assertion is false, you will get a run-time error, a very bad thing.
In typescript, createPortal
receive container of type Element
:
export function createPortal(children: ReactNode, container: Element, key?: null | string): ReactPortal;
Meanwhile, document.querySelector
return an Element OR Null
querySelector<E extends Element = Element>(selectors: string): E | null;
This is a mismatch for both, to fix this, you will need to cast the return object from querySelector
document.querySelector('#overlay-root') as Element,
But for the sake of catching any errors, you should check for null before using it so you won't have to cast at all:
const DisplayCartModal: React.FC<CartModalProps> = (props) => {
const overlayRootEl = document.querySelector('#overlay-root');
return overlayRootEl
? ReactDOM.createPortal(
<>
<CartModal />
</>,
overlayRootEl,
)
: null;
};