Search code examples
typescriptvoid

Detecting that a function returned `void` (rather than `undefined`)


I heard a rumor that void means null|undefined. After all, this code is legal:

var x: void = undefined, y: void = null;

But I'm having a problem that defies this understanding.

EDIT: The problem disappeared when I restarted Visual Studio Code. It turns out that the problem described below occurs only if strictNullChecks is off. I use "strictNullChecks": true so I guess something confused the IDE momentarily, and it was surprising that new errors could be caused by a less strict mode. I should mention that in strictNullChecks mode, var y: void = null is an error. This just leaves me with one question: what's the difference between void and undefined in strict mode?

I wanted to define a callback for a data structure that could return a value, but doesn't have to. Specifically you can return {stop:true} to stop iterating. My code started like this, which didn't work in case the function didn't return a value:

type ForRangeResult = {stop?:boolean} | undefined;
class BTree<K=any,V=any> {
  forEach(callback: (k:K, v:V) => ForRangeResult): number { ... }
  ...
}

// Type 'void' is not assignable to type '{ stop?: boolean; }'.
new BTree().forEach((k,v) => {});

The error message (which itself seems incorrect) disappears if I use

type ForRangeResult = {stop?:boolean} | void;

But it comes back if I use

type ForRangeResult = {stop?:boolean} | undefined | null;

However, if I use {stop?:boolean} | void, how do I check whether the function returned void? The usual control-flow-based typing doesn't work here:

var result = callback(keys[i], values[i]);
if (result !== undefined && result !== null) {
  // [ts] Property 'stop' does not exist on type 'void'
  if (result.stop)
    return ...;
}

I'm inclined to think this is either a compiler bug or an ill-conceived design decision, but is there some easy fix that I am missing?

tsc --version: 2.9.2 (unless IntelliSense version is different)


Solution

  • [ORIGINAL ANSWER]

    This form of your if test avoids the error:

    if (result instanceof Object) {
    

    [BETTER ANSWER]

    if (x !== null && typeof x === 'object') {
    

    This code will not generate compiler errors if x is of type void (undefined).