I am trying to build a modal in my app using NextJS with Typescript, but I can't get rid of the warning on my modal selector. How to correctly type this?
const Modal = ({ children }: ModalProps) => {
const [_document, setDocument] = useState<Document | null>(null);
useEffect(() => {
setDocument(document);
}, []);
if (_document) {
return ReactDOM.createPortal(
<div className={styles.wrapper}>{children}</div>,
_document.querySelector(_document.body)
);
} else {
return null;
}
};
CodePudding user response:
getElementById
returns a nullable value
getElementById(elementId: string): HTMLElement | null;
but ReactDOM.createPortal
only receives non-nullable params
You can be confident about your logic but Typescript is not, so you need to convert those params to non-nullable types for its understanding
const Modal = ({ children }: ModalProps) => {
const [_document, setDocument] = useState<Document | null>(null);
useEffect(() => {
setDocument(document);
}, []);
if (_document) {
return ReactDOM.createPortal(
<div className={styles.wrapper}>{children}</div>,
_document.getElementById("modal") as HTMLElement
);
} else {
return null;
}
};
Or you can use non-null assertion operator
A new ! post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact.
The full change can be
const Modal = ({ children }: ModalProps) => {
const [_document, setDocument] = useState<Document | null>(null);
useEffect(() => {
setDocument(document);
}, []);
if (_document) {
return ReactDOM.createPortal(
<div className={styles.wrapper}>{children}</div>,
_document.getElementById("modal")! //notice `!` at the end of line
);
} else {
return null;
}
};
Just a side note that these changes can cause bugs/errors if your values go undefined/null in some parts of your logic