1

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;
  }
};

enter image description here

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.