Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Optional chaining operator weird behaviour

I am experiencing some weird behaviour in TypeScript (v4.6.2). Why does (a) work but (b) and (c) don’t?

const a: string[] | null = []
if (a?.length > 1) {
    console.log(1)
}

const b = [] as (string[] | null)
if (b?.length > 1) {
    console.log(1)
}

const c: string[] | null = [] as (string[] | null)
if (c?.length > 1) {
    console.log(1)
}

enter image description here

TypeScript playground

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Consider the following:

TS Playground

const a: string[] | null = []
a // string[]
// TS has narrowed this to the array type in the union
// because you assigned an array to the variable after the type annotation

if (a?.length > 1) { // ok
  console.log(1)
}

const b = [] as (string[] | null)
b // string[] | null
// You asserted that the array could be null,
// so it is now possibly null in the type system

if (b?.length > 1) {
//  ~~~~~~~~~
// Object is possibly 'undefined'.(2532)
// TS won't allow comparison of a number to undefined
  console.log(1)
}

const c: string[] | null = [] as (string[] | null)
c // string[] | null
// Another case of assertion

if (c?.length > 1) {
//  ~~~~~~~~~
// Object is possibly 'undefined'.(2532)
// TS won't allow comparison of a number to undefined
  console.log(1)
}

// I suggest one of these patterns instead:
declare const maybeNullMaybeArray: string[] | null;

if ((maybeNullMaybeArray?.length ?? 0) > 1) {
  //                             ^^^^
  // Use nullish coalescing operator to evaluate the expression to 0
  // in the case that it is nullish, so that the comparison will
  // always be between two numbers

  maybeNullMaybeArray // string[] | null
  // but the type is still not narrowed, because the true condition
  // could have resulted from the evaluation to the literal zero
  // instead of a value from the `length` property on the variable
  // so, alternatively:
}

if (maybeNullMaybeArray && (maybeNullMaybeArray.length > 1)) {
  //                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  // The array definitely exists at this point
  // so if we got this far, we can use it as an array:

  maybeNullMaybeArray // string[]
}

See:

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading