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

why doesn't typescript accept if(Array.length) for differentiating between an object and array

I recently started using typescript and I’ve run into a confusing little part, where I don’t quite get why typescript behaves like it does. (Involving typechecking a parameter that could either be an array or an object)

I first tried checking as the upper example shows, but it didn’t work (Typescript didn’t like me calling .map

Error Message: This expression is not callable.
Not all constituents of type ‘string | ((callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[])’ are callable.
Type ‘string’ has no call signatures.ts(2349)

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

I figured it had something to do with calling map on objects so I replaced the condition with Array.isArray() – and suddenly typescript was happy. – But why wasn’t it before? – because in my mind objects wouldn’t be able to pass regardless.

interface Object {
  [key: string]: string
}

function myFunction(a: string[] | Object) {
  if(a.length) {
    a.map(x => x)
  }
}

if I change the condition from a.length to Array.isArray(a) typescript realizes that objects won’t pass this check – but why didn’t it before? (since a.length will return undefined if called on an object – so the check would always fail if a was an object)

So I guess my question is: Why does typescript only accept Array.isArray() as a valid check in this case? – Or is there something else going on I am not aware of?

interface Object {
  [key: string]: string
}

function myFunction(a: string[] | Object) {
  if(Array.isArray(a)) {
    a.map(x => x)
  }
}

>Solution :

Consider the following code:

interface Object {
  [key: string]: string
}

function myFunction(a: string[] | Object) {
  if(a.length) {
    console.log(`I think this is an array: ${a}; it's type is ${typeof a} and it ${Array.isArray(a) ? "is" : "isn't"} an array`);
  } else {
    console.log(`I think this is not an array: ${a}; it's type is ${typeof a} and it ${Array.isArray(a) ? "is" : "isn't"} an array`);
  }
}

myFunction(["a"]);
myFunction({ length: "hello" });

link here

Any object can have the length property, not just arrays. If you want to go down the route of checking for a property, you could just check those you want to use:

interface Object {
  [key: string]: string
}

function myFunction(a: string[] | Object) {
  if(a.hasOwnProperty("map") && typeof a.map === "function") {
    const b = a.map(x => x);
  }
}

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