8

I just started learning TypeScript and in some cases I'm getting an that could be Type or null. Is there an elegant way to deal with these cases?

function useHTMLElement(item: HTMLElement) {
  console.log("it worked!")
}

let myCanvas = document.getElementById('point_file');
if (myCanvas == null) {
  // abort or do something to make it non-null
}
// now I know myCanvas is not null. But the type is still `HTMLElement | null`
// I want to pass it to functions that only accept HTMLElement.
// is there a good way to tell TypeScript that it's not null anymore?
useHTMLElement(myCanvas);

I wrote the following function that seems to work, but this seems like such a common case that I'd like to know if the language itself provides something for this.

function ensureNonNull <T> (item: T | null) : T {
  if (item == null) {
    throw new Error("It's dead Jim!")
  }
  // cast it
  return <T> item;
}
useHTMLElement(ensureNonNull(myCanvas));
Ben
  • 5,952
  • 4
  • 33
  • 44

2 Answers2

2

If you actually do something in the if block to make myCanvas non-null, TypeScript will recognize that:

let myCanvas = document.getElementById('point_fiel');
if (myCanvas == null) {
    return; // or throw, etc.
}
useHTMLElement(myCanvas); // OK

or

let myCanvas = document.getElementById('point_fiel');
if (myCanvas == null) {
    myCanvas = document.createElement('canvas');
}
useHTMLElement(myCanvas); // OK
Ryan Cavanaugh
  • 209,514
  • 56
  • 272
  • 235
2

Typescript typeguards also recognise the instanceof operator - useful when not-null isn't all you need to know

let myCanvas = document.getElementById('point_fiel');
if (myCanvas instanceof HTMLCanvasElement) {
  useHTMLElement(myCanvas);
} else if (myCanvas instanceof HTMLElement) {
  // was expecting a Canvas but got something else
  // take appropriate action 
} else {
  // no element found 
}
balrob
  • 585
  • 6
  • 7