I have a doubt related to typescript, and how I can work with union types to make it work. Currently I have this code:
const message: string | string[] = (axiosError as Error).message
const errorState: string | string[] = Array.isArray(message)
? message[0]
: message
The issue I get is in errorStat variable, I know the cause, it is because I am trying to access message[0] and it can be of type string and have no data inside. I know I always got a value inside message.
Any help?
Thanks!
CodePudding user response:
There are a number of places where this will trip up.
The biggest one is that Array.isArray
and the other answerer's isArray
type guards only assert whether or not the given type is any[]
, not any particular T[]
. If the type guard fails, the type checker knows for sure the type is string
. But if it passes, the type checker only knows that it's any[]
and can't figure out anything beyond that.
If, instead, you had this type guard:
function isTypedArray<T>(val: T | T[]): val is T[] {
return isArray(val);
}
Then the type checker will be able to differentiate between string
and string[]
.
However, you're then storing it in a variable that you have explicitly typed as string | string[]
, so when you subsequently try to use errorMessage
, the type checker will still be confused about the type. Remove the type annotation from errorMessage
, or change it to just string
.
Finally, this might not be an issue for your particular use case, but you have a potential bug if axiosError
's message
field is an empty array. The type checker will assert that you have an array, but then when you try to access the value of it at runtime, it will return as undefined
. That might be acceptable in your situation, but I don't know.
CodePudding user response:
Array.isArray()
is not a typeguard. You can create one of your own using the is
keyword.
Since you only want to check for an array you can use this. Here is an isArray
type-predicate:
let message: string | string[] = 'sdsd';
const isArray = (arg: any): arg is any[] => {
return Array.isArray(arg);
}
const errorState: string | string[] = isArray(message)
? message[0]
: message
Here is an isStringArray predicate for your use:
const isStringArray = (arg: any): arg is string[] => {
for(let i = 0 ; i < arg.length; i ){
if(typeof arg !== 'string')
return false;
}
return Array.isArray(arg);
}