23

I have a response which I am accessing: data?.currentOrganization?.onboardingSteps?. As you can guess, data, currentOrganization, and onboardingSteps might all be null. I want to assign a variable as follows:

const hasSteps = data?.currentOrganization?.onboardingSteps?.length > 0;

I thought hasValue would evaluate to false if any of the fields were null or if there was less than 1 step. However, I get the TypeScript error: Object is possibly 'undefined'.

This is how I am currently getting around it:

const hasSteps =
  data?.currentOrganization?.onboardingSteps != null &&
  data?.currentOrganization?.onboardingSteps?.length > 0;

This feels unnecessarily verbose. Is there an alternative, more elegant solution?

Caleb Robinson
  • 1,010
  • 13
  • 21

1 Answers1

41

The optional chain will end up producing a value for data?.currentOrganization?.onboardingSteps?.length which is presumably a number if everything in the chain is not null or undefined.... but if anything in the chain is nullish, then the output will be undefined itself. You can't test undefined > 0 without Typescript complaining about it.

So you should probably do something like the following:

const hasSteps = (data?.currentOrganization?.onboardingSteps?.length ?? 0) > 0;

This is using nullish coalescing to produce 0 if the optional chain ends in undefined.

Playground link to code

jcalz
  • 264,269
  • 27
  • 359
  • 360
  • Unfortunately though, if you stick this in an if statement, Typscript won't infer that data/currentOrganization/etc are defined, unlike the predecessor, data && data.currentOrganization, etc., which would then satisfy the null/undefined type checking, and allow you to access those properties in the if block. Any way to make that work with this strategy? – chrismarx May 17 '21 at 11:35
  • A comment section on an old question isn't a great place to do this, but: checking `x > 0` doesn't act as a type guard on `x`, but `typeof x === "number"` does, so you can write `if (typeof data?.currentOrganization?.onboardingSteps?.length === "number")` and then the compiler should allow you to access all the intermediate properties separately. If you want to discuss further you might want to post your own question with a [mcve]. Good luck! – jcalz May 17 '21 at 19:27
  • 3
    `undefined > 0` is a valid expression yielding `false` on any JavaScript engine. It's unclear why it fails in TypeScript. – AxeEffect Oct 26 '21 at 16:06
  • 1
    Looks like you want https://github.com/microsoft/TypeScript/issues/45543 . Note that "it works in JS so it should work in TS" is not going to convince the TS team. See https://stackoverflow.com/q/41750390/2887218 . The argument would need to be more like "comparisons like `x > 0` where `x` might be `undefined` is widely used in idiomatic real-world JavaScript", along with supporting evidence. – jcalz Oct 26 '21 at 17:34