8

How to do an array check (like Array.isArray()) with a readonly array (ReadonlyArray)?

As an example:

type ReadonlyArrayTest = ReadonlyArray<string> | string | undefined;

let readonlyArrayTest: ReadonlyArrayTest;

if (readonlyArrayTest && !Array.isArray(readonlyArrayTest)) {
  // Here I expect `readonlyArrayTest` to be a string
  // but the TypeScript compiler thinks it's following:
  // let readonlyArrayTest: string | readonly string[]
}

With an usual array the TypeScript compiler correctly recognises that it must be a string inside the if condition.

2 Answers 2

10

Here's relevant issue in typescript.

Suggested workaround by @jcalz is adding overload to declaration of isArray:

declare global {
    interface ArrayConstructor {
        isArray(arg: ReadonlyArray<any> | any): arg is ReadonlyArray<any>
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, but where should I put that interface declaration? It's not working if I just paste it into the file where the issue appears.
@mamiu inside module you'll need to wrap this in "global declaration". See stackoverflow.com/questions/47130406/…
Amazing! Posted this answer on the Github issue.
Should really be arg is ReadonlyArray<any> | any[], since arg might not be a ReadonlyArray.
@AlekseyL. ReadonlyArray<any> | Readonly<any> to not overriding default declaration
2

it should be like this

interface ArrayConstructor {
  isArray(arg: unknown): arg is unknown[] | readonly unknown[];
}

and test it in typescript

const a = ['a', 'b', 'c'];
if (Array.isArray(a)) {
  console.log(a); // a is string[]
} else {
  console.log(a); // a is never
}

const b: readonly string[] = ['1', '2', '3']

if (Array.isArray(b)) {
  console.log(b); // b is readonly string[]
} else {
  console.log(b); // b is never
}

function c(val: string | string[]) {
  if (Array.isArray(val)) {
    console.log(val); // val is string[]
  }
  else {
    console.log(val); // val is string
  }
}

function d(val: string | readonly string[]) {
  if (Array.isArray(val)) {
    console.log(val); // val is readonly string[]
  }
  else {
    console.log(val); // val is string
  }
}

function e(val: string | string[] | readonly string[]) {
  if (Array.isArray(val)) {
    console.log(val); // val is string[] | readonly string[]
  }
  else {
    console.log(val); // val is string
  }
}

Comments

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.