I'm using React and TypeScript. When I'm iterating through an array using map(), it seems the types are not always checked. In the following example I pass a string "more" into the eachItem function, where number is expected. But no error is thrown:
function eachItem(val: number, i: number) {
return Number(val) / 2;
}
const arr = [4, "more", 6];
arr.map(eachItem);
I think I understand why this happens, but my question is how I can make strict typing on a map function, so that I get this error when passing in the string:
Argument of type 'string' is not assignable to parameter of type 'number'
Why no error is thrown is because I'm giving a callback to the map(). This map() expects a callback of this type:
'(value: string | number, index: number, array: (string | number)[]) => Element'
and I'm giving a callback of this type:
'(item: number, i: number) => Element'
So instead of checking whether 'number' includes 'string | number', TypeScript checks whether 'string | number' includes 'number' and finds it true. My logic says we need an error, since I'm passing "more" where only numbers are permitted. TypeScript's logic says no error, I'm passing a function that allows numbers where functions that allow strings and numbers are permitted. It doesn't seem to be a big issue, but when your type is a union, you get errors when you're not supposed to. This is an example, and the resulted error:
interface IMoney {
cash: number;
}
interface ICard {
cardtype: string;
cardnumber: string;
}
type IMix = IMoney | ICard;
const menu = [
{cash: 566},
{cardtype: "credit", cardnumber: "111111111111111111"}
];
menu.map((item: IMix, i: number) => (item.cash || item.cardtype));
Property 'cash' does not exist on type 'IMix'.
Property 'cash' does not exist on type 'ICard'.
I know, now I have to do the following, but then I can't express in my code that cash and cardtype exclude each other:
interface IMix {
cash?: number;
cardtype?: string;
cardnumber?: string;
}