Given the following:
type Arr = (0|1)[]
const arr: Arr = [0, 1]
const someNumber: number = 5;
arr.includes(someNumber);
// ^^^^^^^^^^
// Argument of type 'number' is not assignable to parameter of type '0 | 1'.
Is there a way to make arr.includes(someNumber)
work for TypeScript without changing the definition of Arr
or doing some type casting?
Doesn't this error defeat the purpose of using Array.prototype.includes()
?
The
includes()
method determines whether an array includes a certain value among its entries, returningtrue
orfalse
as appropriate.
CodePudding user response:
Doesn't this error defeat the purpose of using Array.prototype.includes()?
Not really. It's just TypeScript doing its job: making the code typesafe. You've said that arr
can only include the values 0
or 1
, so calling includes
with a value that can't be in the array is a type error. (That said, I could definitely see an argument for includes
to accept number
instead of 0 | 1
in a case like that. I suspect there are counter-arguments though.)
You could write a utility function to check if a number
is a valid element for arr
:
const isValidArrElement = (value: number): value is Arr[number] => {
return value === 0 || value === 1;
};
Then use that before using includes
:
const arr: Arr = [0, 1]
const someNumber: number = 5;
if (isValidArrElement(someNumber) && arr.includes(someNumber)) {
// ...
}
But I usually prefer to approach this the other way so that I'm not writing the 0
and 1
in two places and creating a maintenance hazard:
const validArrElements = [0, 1] as const;
type ArrElement = (typeof validArrElements)[number];
// ^? -- type is 0 | 1
const isValidArrElement = (value: number): value is ArrElement => {
return (validArrElements as readonly number[]).includes(value);
};
Note that isValidArrElement
does have a type assertion in it. I'm not bothered about that, because I only do this in these pairs of things (constant arrays of valid values and type checkers for them).
The usage is the same as above:
const arr: Arr = [0, 1]
const someNumber: number = 5;
if (isValidArrElement(someNumber) && arr.includes(someNumber)) {
// ...
}
CodePudding user response:
You defined a union type consisting of 0 | 1
which means your array values will be type-guarded with value 0
or 1
. That's how union types work in Typescript.
The usual array will be defined with a primitive type like below
const arr: Array<number> = [0, 1]
That is one of choices
But if you still want to go with your union type definition, you can cast it to number[]
which allows all numbers being used in array's functions
type Arr = (0|1)[]
const arr: Arr = [0, 1]
const someNumber: number = 5;
(arr as readonly number[]).includes(someNumber) //correct
const someString: string = "5";
(arr as readonly number[]).includes(someString) //error
CodePudding user response:
let scores : (string | number)[];
scores = ['Programming', 5, 'Software Design', 4];
const someNumber: number = 5
console.log('scores.includes(someNumber)', scores.includes(someNumber))
It's returing True