Using a juggling-check, you can test both null and undefined in one hit:

if (x == null) {

If you use a strict-check, it will only be true for values set to null and won't evaluate as true for undefined variables:

if (x === null) {

You can try this with various values using this example:

var a: number;
var b: number = null;

function check(x, name) {
    if (x == null) {
        console.log(name + ' == null');
    }

    if (x === null) {
        console.log(name + ' === null');
    }

    if (typeof x === 'undefined') {
        console.log(name + ' is undefined');
    }
}

check(a, 'a');
check(b, 'b');

Output

"a == null"

"a is undefined"

"b == null"

"b === null"

Answer from Fenton on Stack Overflow
🌐
MDN Web Docs
developer.mozilla.org β€Ί en-US β€Ί docs β€Ί Web β€Ί JavaScript β€Ί Reference β€Ί Operators β€Ί Nullish_coalescing
Nullish coalescing operator (??) - JavaScript | MDN
The nullish coalescing operator treats undefined and null as specific values. So does the optional chaining operator (?.), which is useful to access a property of an object which may be null or undefined.
Discussions

[AskJS] Nullish Check in conditional
value == null only matches null and undefined, not any other falsy values. This is the only time you should use == over ===. More on reddit.com
🌐 r/javascript
23
7
August 16, 2024
Safely casting away nullishness in typescript - Stack Overflow
But two things: 1. It's easy for ... nullish value. So in this case, it's probably fine if the null case is to throw an error. But if you aren't paying close attention and use it wrong, the typescript compiler won't help you. 2. The assertion is only good for that line, where if you check it properly, ... More on stackoverflow.com
🌐 stackoverflow.com
How to use Nullish Coalescing in Typescript
With the release of Typescript 3.7 there is now support for Nullish Coalescing. However it seems like I am using it wrongly.. More on stackoverflow.com
🌐 stackoverflow.com
Nullish Coalescing Operator vs Logical OR
They are different, if you want value=0 to fall back to 1 you should use || otherwise use ?? More on reddit.com
🌐 r/typescript
4
2
July 13, 2022
🌐
TypeScript
typescriptlang.org β€Ί play β€Ί 3-7 β€Ί syntax-and-messaging β€Ί nullish-coalescing.ts.html
TypeScript: Playground Example - Nullish Coalescing
The nullish coalescing operator is an alternative to || which returns the right-side expression if the left-side is null or undefined. In contrast, || uses falsy checks, meaning an empty string or the number 0 would be considered false.
🌐
W3Schools
w3schools.com β€Ί typescript β€Ί typescript_null.php
TypeScript Null & Undefined
TypeScript has a powerful system to deal with null or undefined values.
🌐
Reddit
reddit.com β€Ί r/javascript β€Ί [askjs] nullish check in conditional
r/javascript on Reddit: [AskJS] Nullish Check in conditional
August 16, 2024 -

I feel like an idiot as this feels like it should be an obvious answer, but every time this has come up I've failed to think of a satisfactory answer, and google with such basic terms is useless.

If I have a value that I want to put in a full conditional (an if() ) to check if it is nullish (null or undefined) but not falsy, what's a clean, concise, and clear syntax?

We have the nullish coallescing operator, but that acts like the ternary/conditional operator and not like a comparison operator. If I have a block of statements I want to run IF the value is nullish (or if it is NOT nullish) but not falsy, I don't feel like I have any option other than to say the explicit if ( value === undefined || value === null ) {...}

I can write my own isNullish() or use constructs like if( !(value ?? true) ) { ...} but these are awful, and I feel like I must be missing something obvious.

This obviously isn't a big deal, checking the two values isn't terrible, but is there something I'm missing that lets me say if( ??nullish ) { ... } when I have more than simple defaulting to do?

[Edit: The answer I was seeking is value == null or value == undefined, as these specific checkes are an exception to the normal practice of avoiding loose comparison, if nullish is what I want to check for. Thanks for the help, I was indeed missing something basic]

🌐
TypeScript
typescriptlang.org β€Ί docs β€Ί handbook β€Ί release-notes β€Ί typescript-3-7.html
TypeScript: Documentation - TypeScript 3.7
Likewise, if baz is null or undefined, we’ll hit an error at the call site. ?. only checks for whether the value on the left of it is null or undefined - not any of the subsequent properties. You might find yourself using ?. to replace a lot of code that performs repetitive nullish checks using ...
🌐
DEV Community
dev.to β€Ί danywalls β€Ί simplify-your-typescript-code-with-optional-chaining-and-nullish-coalescing-37on
Simplify Your Typescript Code with Optional Chaining and Nullish Coalescing - DEV Community
May 23, 2023 - The double question mark (??) checks if the left-hand side value is nullish (null or undefined) and provides the right-hand side value as the default if needed. Nullish coalescing ensures that we always have a valid jersey number, even if it's ...
Find elsewhere
🌐
Omarileon
omarileon.me β€Ί blog β€Ί typescript-null-undefined
mari. | How to Detect Null and Undefined in Your TypeScript Code
February 27, 2024 - Another way to check for null or undefined is to use the nullish coalescing operator (??), which was introduced in TypeScript 3.7. If the left-hand side of the operation is non-null it returns that, otherwise it returns the right-hand side otherwise.
🌐
Oxidation Compiler
oxc.rs β€Ί docs β€Ί guide β€Ί usage β€Ί linter β€Ί rules β€Ί typescript β€Ί prefer-nullish-coalescing
typescript/prefer-nullish-coalescing
The nullish coalescing operator (??) only returns the right-hand side when the left-hand side is null or undefined, making the intent clearer and avoiding bugs with other falsy values.
Top answer
1 of 2
4

"For example, I could write someObject?.someProperty?.someMethod() which makes the error go away; but it ignores the fact that it is almost always an error if any of those null coalescing operators have effect."

If having a null value there is an exceptional situation, then your types should not allow that null. It sounds like your types are too permissive. If it's an error when the value is null, then it stands to reason it should be a type error when the value is null.

Dealing with nullish values is something that we all have to deal with, but it's really hard to generalize about since what to do in the null case is very dependent on how your app/code works.


In general, when I have properties that need be non-null most of the time, I declare them as such.

interface MyType {
  someObject: {
    someProperty: {
      someMethod(): void
    }
  }
}

And then only make the fields optional when required for that circumstance:

function makeMyType(values: Partial<MyType>): MyType {
  return { ...defaultMyType, ...values }
}

Sometimes it can't really be avoided easily, and in this cases I do end up doing a lot this:

if (!foo) throw new Error('really expected foo to be here!')
console.log(foo.bar)

Or in some cases just:

if (!foo) return
console.log(foo.bar)

Which is fine. If it ever really is nullish, then you get a nice error message about what went went wrong. Or, in the second case, you just bail from a function that would be invalid in the null case.


It's hard to advise more specifically without the details of your types. But in the end if:

"it seems like a non-negligble portion of my code is dealing with nullish-able variables"

then I would look at your types first to make sure you remove as much nullishness as you can.


Another option is to use a type predicate function to validate whole objects which you can then use without testing every single property everywhere:

interface Foo {
  foo: string
  bar: string
  baz: string
}

function validateFoo(maybeFoo: Partial<Foo>): maybeFoo is Foo {
  return !!maybeFoo.foo && !!maybeFoo.bar && !!maybeFoo.baz
}

const partialFoo: Partial<Foo> = { bar: 'a,b,c' }
if (validateFoo(partialFoo)) {
  partialFoo.bar.split(',') // works
}

Playground

2 of 2
4

I marked Alex Wayne's answer, above, as the accepted answer. It makes a lot of useful points about pain I've inflicted on myself.

But I'd like to take a moment to extol the virtues of nullCast, which has worked out far better than I expected.

function nullCast<TYPE>(value: TYPE | null | undefined) : TYPE
{
   if (!value) throw Error("Unexpected nullish value.");
   return value;
}

The principal beautify of nullCast is that one never needs to supply the template parameter. TypeScript will correctly infer the non-nullish return type automatically. This works.

  class Foo {
      optionalBarValue?: Bar;

      getBarValue() : Bar {
          // no explicit template parameter required.
          return nullCast(this.optionalBarValue); 
      }
  };

where "correct" means an exception will be thrown at runtime if this.optionalBarValue is undefined, and the automatically inferred return type of nullCast() at compile time is Bar, with any combination of | null, and | undefined stripped away.

Unlike the null-assertion operator '!' which produces no runtime code at all, nullCast does generate code, and does throw definitively. Compare

  let value: TYPE = this.objMember!.member!;
    // no effect at runtime'. An error is throw if .objMember 
    // evaluates to null or undefined, but no exception is thrown
    // if .member is nullish. The value variable ends up 
    // holding a value at runtime that is not of correct type.

   let value: TYPE = nullCast(this.objMember?.member);
     // Throws convincingly at runtime if either .objMember 
     // or .member evaluate to nullish. The inferred return type
     // of .member is non-nullish concrete type of .member.

There's nothing terribly wrong with using if statements to remove nullishness in following code. But it is intrusive, and has a negative effect on compactness and legibility. If your intention is to throw an error when nullish assumptions are violated, nullCast can be used compactly and efficiently inline when evaluating expressions, while still maintaining clear visiblity for readability purposes. e.g.:

let value1 = nullCast(this.member1);
let value2 = nullCast(this.member2.function()?.member);

or even (somewhat hesitantly)

let value = nullCast(this.function1)(arg1,arg2);

Motivation: One still needs to evaluate on a case-by-case basis what the correct response to a nullish value is. But the brutal easiness of if (!value) return; makes it far too easy to do the wrong thing. If a nullish value violates an assumption in code, the correct response is to throw at runtime, rather than return without regard for the delayed consequences of not doing what should have been done. nullCast, in certain cases, makes it easier to do the right thing.

Anyway. Back to doing my homework on type predicates.

Top answer
1 of 2
5

It's a precedence issue. Your code is being evaluated as:

if (data?.["myKeys"]?.indexOf("index1") ?? (-1 === -1)) {
// βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’^βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’^
    console.log("Why is it true");
}

but your intention is:

if ((data?.["myKeys"]?.indexOf("index1") ?? -1) === -1) {
// βˆ’^βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’^
    console.log("Why is it true");
}

Oddly, I don't see precedence discussed in the proposal though it is mentioned in the draft spec as Jonas mentions, and it does come up in the issues.

As you can see, this is consistent with the precedence of ||, which is its very, very near relative:

const a = 2;
const b = -1;
console.log(`${a} || ${b} === ${b}:   ${a || b === b}`);
console.log(`(${a} || ${b}) === ${b}: ${(a || b) === b}`);
console.log(`${a} || (${b} === ${b}): ${a || (b === b)}`);

According to the draft spec, ?? has lower precedence than || (presumably just lower). (To avoid confusion, it's also not allowed in an && or || expression.)

2 of 2
3

To quote from the draft:

?? has lower precedence than ||

Or in other words, your code behaves roughly like:

  data?.["myKeys"]?.indexOf("index0") || -1 === -1

And that'll be treated as:

 (data?.["myKeys"]?.indexOf("index0")) || (-1 === -1)
🌐
GeeksforGeeks
geeksforgeeks.org β€Ί typescript β€Ί nullish-coalescing-operator-in-typescript
Nullish Coalescing Operator (??) in TypeScript - GeeksforGeeks
July 23, 2025 - The nullish coalescing (??) operator is a logical operator in TypeScript that returns its right-hand side operand if the left-hand side operand is null or undefined; otherwise, it returns the left-hand side operand.
🌐
egghead.io
egghead.io β€Ί lessons β€Ί typescript-use-the-nullish-coalescing-operator-in-typescript
Use the Nullish Coalescing Operator in TypeScript | egghead.io
This lesson introduces the ?? operator which is known as nullish coalescing. The ?? operator produces the value on the right-hand side if (and only if) ...
Published Β  February 17, 2021
🌐
Medium
medium.com β€Ί @ambily_francis β€Ί unlocking-typescripts-nullish-coalescing-d00ef1db698a
Unlocking TypeScript’s Nullish Coalescing | by Ambily Francis | Medium
March 11, 2024 - In this example, the variable `username` is assigned the value `null`. When using nullish coalescing (`??`), if the value of `username` is `null` or `undefined`, the expression evaluates to the provided default value `’Guest’`. As a result, `defaultUsername` is assigned the value `’Guest’`.
🌐
JavaScript in Plain English
javascript.plainenglish.io β€Ί understanding-nullish-non-nullish-and-asserting-non-nullish-values-in-typescript-5a753fa0254d
Understanding Nullish, Non-Nullish, and Asserting Non-Nullish Values in TypeScript | JavaScript in Plain English
August 3, 2023 - In TypeScript, the term β€œnullish” refers to values that are null or undefined. These values represent the absence of a value. By default, variables are nullable (meaning they can hold these nullish values), unless you explicitly specify them as non-nullable using the type annotations or ...
🌐
Marius Schulz
mariusschulz.com β€Ί blog β€Ί nullish-coalescing-the-operator-in-typescript
Nullish Coalescing: The ?? Operator in TypeScript β€” Marius Schulz
August 14, 2021 - TypeScript 3.7 added support for the ?? operator, which is known as the nullish coalescing operator. We can use this operator to provide a fallback value for a value that might be null or undefined.
🌐
TypeScript ESlint
typescript-eslint.io β€Ί rules β€Ί prefer-nullish-coalescing
prefer-nullish-coalescing | typescript-eslint
*/ boolean?: boolean; /** Ignore number primitive types. */ number?: boolean; /** Ignore string primitive types. */ string?: boolean; } /** Ignore all primitive types. */ | true; /** Whether to ignore any ternary expressions that could be simplified by using the nullish coalescing operator.
🌐
Frontend Masters
frontendmasters.com β€Ί courses β€Ί intermediate-typescript-v2 β€Ί optional-chaining-nullish-coalescing
Optional Chaining & Nullish Coalescing - Intermediate TypeScript, v2 | Frontend Masters
Mike explains the concept of optional chaining and demonstrates how to access nested properties using optional chaining. The concept of nullish coalescing and how it can be used to set default values …
🌐
Reddit
reddit.com β€Ί r/typescript β€Ί nullish coalescing operator vs logical or
r/typescript on Reddit: Nullish Coalescing Operator vs Logical OR
July 13, 2022 -

Take this interface for example

interface Item {
  value?: number
}

Which among the two do you prefer if you will be accessing the value property of an item and why?

console.log(item.value ?? 1.00) // 1.00 is the fallback value
console.log(item.value || 1.00) // 1.00 is the fallback value

Personally, I prefer to use the nullish coalescing operator ?? for fallback values since it's more explicit and it sames me from the weird falsy values that JavaScript has.

🌐
Typescript-training
typescript-training.com β€Ί course β€Ί fundamentals-v3 β€Ί 13-nullish-values
Nullish values | Learn TypeScript w/ Mike North
June 8, 2021 - There are situations where we have to plan for, and deal with the possibility that values are null or undefined. In this chapter we’ll dive deep into null, undefined, definite assignment, non-nullish coalescing, optional chaining and the non-null assertion operator.