5

In Typescript I am checking if an object's properties are null as follows:

var addressCountryName = response.address == null 
   ? null 
   : response.address.country == null ? null : response.address.country.name;

Both addresses and country can be null ... I also tried:

var addressCountryName = response.address?.country?.name;

This does not seem to work ...

Is there a shortest way to check for null / undefined?

3
  • What does "doesn't work" mean? Commented Jan 24, 2019 at 19:54
  • 2
    The JavaScript null coalescing operator is just a proposal for now, so nothing is built into the language. Commented Jan 24, 2019 at 19:57
  • 1
    There is no safe null-coalescing operator in TypeScript yet. Commented Jan 24, 2019 at 19:57

3 Answers 3

4

There is currently no null coalescing operator in JavaScript. There are different ways to get around it (like your nested ternary types). If you're willing to shove helper types and functions into a library somewhere, you could do this:

type MyResponse = {
  address?: null | {
    country?: null | {
      name?: null | string
    }
  }
}

let response: MyResponse = Math.random() < 0.5 ? 
  { address: { country: { name: "France" } } } : { address: null }

var addressCountryName = nullSafe(response, r => r.address.country.name); 
// string | undefined | null

Where nullSafe() is defined like this:

interface NullSigil {
  [k: string]: NullSigil;
}

// phantom property to recover T from NullSafe<T>
type OriginalTypeKey = "***originalType***"

type IsNullable<T, Y, N> = null extends T ? Y :
  undefined extends T ? Y : N;

type NullSafe<T, N = NullSigil> = Record<OriginalTypeKey, T> & (
  T extends object ? {
    [K in keyof T]-?: NullSafe<T[K], N>
  } : IsNullable<T, NonNullable<T> | N, T>
)

type NullUnsafe<T> =
  T extends Record<OriginalTypeKey, infer U> ? U :
  T extends NullSigil ? null :
  T

function nullSafe<T, U>(
  val: T,
  fn: <N extends NullSigil>(nullSafeVal: NullSafe<T, N>) => U
): NullUnsafe<U>;
function nullSafe(val: any, fn: (nullSafeVal: any) => any): any {

  const nullSigil: NullSigil = new Proxy({} as NullSigil, { get(t, p, r) { return r } });
  const deproxify = Symbol("deproxify");

  function ns<T>(obj: T): NullSafe<T>;
  function ns(obj: any) {
    if ((typeof obj === "undefined") || (obj === null)) return nullSigil;
    if (typeof obj !== "object") return obj;
    return new Proxy(obj, { get(t, p, r) { return (p === deproxify) ? t : (p in t) ? ns(t[p]) : nullSigil } });
  }

  const ret: any = fn(ns(val));

  if (ret === nullSigil) return null;
  if (typeof ret !== "object") return ret;
  return ret[deproxify];
}

Yes, it's a mess, that's why I said to shove it into a library. It works by making a Proxy that always allows you to drill down into properties even if it is essentially null.

Anyway, it's one option. Good luck!

Sign up to request clarification or add additional context in comments.

Comments

2

As others have mentioned the null coalescing operator is still in a proposal stage so you can't access properties using ?. Your only options currently are to do deep nesting with if statements or ternarys or to consider something like the get method from lodash which would let you do:

let addressCountryName = get(response, 'address.country.name');

Which will either return the value of name or undefined if any part of the object path was null or undefined.

Here's a CodeSandbox with an example of using lodash: https://codesandbox.io/s/mm46wkr058

Comments

0

! is the non-null assertion operator in Typescript. ? is for Angular html templates.

2 Comments

The non-null assertion operator does something entirely different from what OP wants.
Not sure what you mean ... You mean to use this: response.address!.country!.name? Does not work ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.