27

Edit: I'm using TypeScript v2.2.1

I am new to TypeScript and I'm not sure what the cleanest way of dealing with DOM elements that may or may not exist is. Basically, I want to check whether an element exists, and then if it does, add an event listener to it (I have --strict_null_checks turned on).

When I do it the JS-like way:

const myElement = document.getElementById('my-id');
if (myElement) {
  myElement.addEventListener('click', (e:Event) => {
    // Do stuff.
  });
}

I get the error my_script.ts(3, 3): error TS2531: Object is possibly 'null'.

I can get around this by using a not-null assertion:

const maybeMyElement = document.getElementById('my-id');
if (maybeMyElement) {
  const myElement = maybeMyElement!;
  myElement.addEventListener('click', (e:Event) => {
    // Do stuff.
  });
}

But my understanding is that those sorts of assertions are generally frowned upon, and aesthetically, I don't like creating twice as many variables.

Is there a cleaner way to do this?

Evan Hefner
  • 377
  • 1
  • 3
  • 5
  • What version of the Typescript compiler are you using? Your first example works as expected for me (with `strictNullChecks` on). – y2bd Apr 04 '17 at 23:21
  • Oops, sorry I forgot to mention the version. I'm using version 2.2.1. – Evan Hefner Apr 05 '17 at 19:53

4 Answers4

33

You should type your variables. I haven't done a lot with const, but your second options seems plain wrong (code-smell).

You should be able to get around the warning by strictly typing the variable. The compiler currently sees this as

const myElement: HTMLElement = document.getElementById('my-id');

If you change it to also possibly be null, then nulls are allowed:

const myElement: HTMLElement | null = document.getElementById('my-id');

Updated

Second option (that I haven't tried): use the ! at the end of the potentially null operation, per https://stackoverflow.com/a/40640854/2084315

const myElement = document.getElementById('my-id')!;
Community
  • 1
  • 1
ps2goat
  • 8,067
  • 1
  • 35
  • 68
6

Use Optional chaining "?"

Starting TypeScript version 3.7+ you can use Optional Chaining

const maybeMyElement = document.getElementById('my-id');
maybeMyElement?.addEventListener('click', (e: Event) => {
  // Do stuff.
  console.log(e);
});

For older version of TypeScript we would do something like

const maybeMyElement = document.getElementById('my-id') as HTMLElement;
maybeMyElement.addEventListener('click', (e: Event) => {
  // Do stuff.
  console.log(e);
});

Note: Optional chaining (??) is always preferred over non-null assertion operator (!) as non-null assertion can actually lead to run time error if the value comes out to be null or undefined.

And, if you have "plugin:@typescript-eslint/recommended" configured in your eslint settings you will get "Forbidden non-null assertion" warning in your code.

5

Try using the following:

if (!!myElement) {
    myElement.addEventListener('click', (e:Event) => {
        // Do stuff.
    });
}

The !! coerces an object expression into a boolean. It's the ! operator twice. For more info on this, see this answer

  • try editing your answer so I remove the downvote. I inadvertently clicked the downvote button by mistake and can't seem to undo it. – abidmix Oct 27 '17 at 20:17
0

if you're using referring to external JS file, then try adding "defer" in your script syntax. eg:

<script src="./script.js" defer></script>
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61