ChatGPT解决这个技术问题 Extra ChatGPT

Typescript, how to pass "Object is possibly null" error?

I've got the "Object is possibly null" error many times and usually I use a safety "if statement" in case it returns null.

I've got the following function:

const ModalOverlay = (props: any[]) => {
  const overlayEl = useRef(null);
    useEffect(() => {
    overlayEl.current.focus();
    });
    return <div {...props} ref={overlayEl} />;
  }

But overlayEl.current gets the error "Object is not defined". So I've tried:

if (!overlayEl) {
    return null
  } else {
    useEffect(() => {
    overlayEl.current.focus();
    });
    return <div {...props} ref={overlayEl} />;
  }

Which didn't work. I've tried also:

overlay && overlayEl.current.focus();

Any hints would be highly appreciated! Thanks

Hi, you should check for null before trying to call focus method if ( overlay && overlay.current ) { overlayEl.current.focus(); }

S
Shanon Jackson

When you declare const overlayEl = useRef(null); Makes the type it comes out as is null because that's the best possible inference it can offer with that much information, give typescript more information and it will work as intended.

Try....

 const overlayEl = useRef<HTMLDivElement>(null);

Alternatively some syntax sugar for if you don't care for when its undefined is to do something like this.

const overlayEl = useRef(document.createElement("div"))

using the above syntax all common DOM methods just return defaults such as "0" i.e overlayEl.offsetWidth, getBoundingClientRect etc.

Usage:

if(overlayEl.current) {
    // will be type HTMLDivElement NOT HTMLDivElement | null
    const whattype = overlayEl.current; 
}

The way this works is typescripts static analysis is smart enough to figure out that if check "guards" against null, and therefore it will remove that as a possible type from the union of null | HTMLDivElement within those brackets.


I think it's all important to mention that you also have to check for null before using current, as @thisismydesign pointed out.
Giving typescript more information was a good idea.
T
TargetTaiga
const overlayEl = useRef() as MutableRefObject<HTMLDivElement>;

It will cast overlayEl to an initiated MutableRefObject that is the returning value of useRef:

function useRef<T = undefined>(): MutableRefObject<T | undefined>;

Yet in this case, the compiler will always think that overlayEl has a value.


Thank you. At least for me, this was the correct answer. Note that if your element is an input you'll need to use [...] = useRef() as MutableRefObject<HTMLInputElement>
Thanks, this one saved me. Other answers do not take into account cases like where you need to reassign .current
document.createElement("div") will get error on first render (error about document is undefiend)
t
thisismydesign

Add a type to the ref as mentioned by @Shanon Jackson:

const linkRef = useRef<HTMLLinkElement>(null);

And then, make sure you check for null value before using current:

if (linkRef.current !== null) {
  linkRef.current.focus();
}

This will satisfy Typescript. Whereas either by itself wouldn't.

Using any or casting in order to "trick" the compiler defeats the purpose of using Typescript, don't do that.


s
stackoverflow

If you want to "pass/skip" then this will do it const overlayEl: any = useRef(null);


I just did ... and it passed! Doesn't sound like a good advice in general. In particular, casting to any jeopardises the purpose of having types - it makes overlayEl any type possible, so all the type information is lost. any type is like not type at all (vanilla js).
yes indeed, this is a workaround I've found just to make it working. I didn't said it's the way to go, or the best :) As you can see, the question is "How to pass" which can indicate "How to skip", not how to fix...but that's another thing
it's really not good advice. you should avoid using any in typescript. you might as well be using javascript
yeah, I'm not a fan of any
Also works: const overlayEl = useRef(null as any);
r
rosmcmahon

I think this is more succinct than the other answers here:

const ModalOverlay = (props: any[]) => {
  const overlayEl = useRef<HTMLDivElement>(null);
  useEffect(() => {
    overlayEl.current!.focus();
  });
  return <div {...props} ref={overlayEl} />;
}

You specify the type of the reference, and you state you know it's not null.


Imo this is a better solution than the marked answer.
A
AbdulSamad

You can also use optional chaining which is introduced in ES2020 instead of "if" statement for cleaner code

const myRef = useRef<HTMLLinkElement>(null);

myRef.current?.focus();

You can check its browser support at caniuse.


N
Nikola Lukic

If you really know that in executing time you dont have a error here then just put :

 (overlayEl as any).current 

If not, better use:

    if (typeof overlayEl !== 'undefined' &&
      typeof overlayEl.current !== 'undefined' &&
      overlayEl.current === null) {          
      return;
    }

    // Or

    try {
      // you code here ...
      // This is fine way to check by order -> parent.parent.FinalInstance
      // Also try & catch will handle all bad situation about current error
      overlay &&  overlayEl.current && overlayEl.current.focus();

    } catch(e){
       console.log("Real null >> ", e);     
    }

  // Suggest if i am wrong in syntax somewhere ,this is fast answer ;)

Unfortunately typeof null is equal to object and not to "null" and definitely not null.
I dont write this, it is from question. Maybe you are right.
M
Maifee Ul Asad

Sometimes we useRef not only to hold an element but a value like data. somehow when I check if(something.current) return something.current not working even if i add && something.current!=null so i found that:

something.current! which says to typescript i know there is a value and bypass this issue.


k
kadiro

if you want to give no chance to typescript use this :

const iframe = useRef<HTMLIFrameElement | null>(null);

     if (
   typeof iframe !== "undefined" &&
   typeof iframe.current !== "undefined" &&
   iframe.current !== null
 ) {
   iframe?.current?.contentWindow='';
   );
 }

P
PeterMoelker

Depends on what you prefer but a nice syntax and structure might be to create an interface:

interface divEL {
  current: HTMLDivElement | null;
}

This will keep your declaration clear and short and you can reuse the divEl interface for similar useRef hooks.

const overlayEl: divEL = useRef(null);

Then add focus() like this:

overlayEl.current!.focus();