2

In a method, I have a type with a possible value of an array. However, before I access the argument, I check to ensure that the argument isn't an array.

I still get the following error (excerpt) on line this.setState({ cuisine });:

Type 'readonly SelectOption[]' is missing the following properties from type 'SelectOption': value, label

When I hover over cuisine on the error line, the type determined by VS Code is SelectOption | readonly SelectOption[]

Here's the code:

interface SelectOption {
  value: number | string;
  label: string
}

private onCuisineChange(cuisine: ValueType<SelectOption>): void {
    if (Array.isArray(cuisine) && cuisine.length > 1)  {
        throw new Error(`Expected cuisine to be an object, but got ${cuisine}`);
    }

    if (cuisine) {
        this.setState({ cuisine });
    } else {

    }
}


Using TS version 3.5.3

1 Answer 1

3

TypeScript is correctly inferring the type here. In addition to the array check, there is the condition && cuisine.length > 1. This means that the exception is only thrown if cuisine is an array with more than one element in it.

The lower if statement could still be executed where cuisine is an empty array or array with a single element hence the type SelectOption | readonly SelectOption[].

With that being said, as of 3.5.1, TypeScript#17002 (thanks @SeanVieira) is still open about Array.isArray not narrowing readonly arrays. A workaround provided there is to include, somewhere in your project's declarations, an overload to tell typescript that it should in fact narrow readonly arrays as well:

From https://stackoverflow.com/a/56249765/10609635

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

3 Comments

There is an interesting problem in that even without the extra check, Array.isArray is not enough to narrow the type. This also looks like a genuine bug with TS, since adding interface ArrayConstructor { isArray(value: any): value is readonly any[]; } resolves the second issue.
I did have just an Array.isArray check as well and get the same error. Thanks for the issue link, @SeanVieira. I did a quick search but failed to find it.
Yes @SeanVieira, the link is much appreciated. Let me collect some of that and put it into the answer.

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.