我正在使用 React 和 TypeScript。当我使用 map() 迭代数组时,似乎并不总是检查类型。在下面的示例中,我将字符串“more”传递到eachItem 函数中,其中需要数字。但没有抛出错误:
function eachItem(val: number, i: number) {
return Number(val) / 2;
}
const arr = [4, "more", 6];
arr.map(eachItem);
我想我明白为什么会发生这种情况,但我的问题是如何在地图函数上进行严格的输入,以便在传入字符串时出现此错误:
“字符串”类型的参数不可分配给“数字”类型的参数
为什么没有抛出错误是因为我给了map()回调。这个map()需要这种类型的回调:
'(value: string | number, index: number, array: (string | number)[]) => Element'
我正在给出这种类型的回调:
'(item: number, i: number) => Element'
因此,不要检查“数字”是否包含“字符串”| number',TypeScript 检查是否为 'string | number' 包含 'number' 并发现它为真。我的逻辑表明我们需要一个错误,因为我在只允许数字的地方传递了“更多”。 TypeScript 的逻辑表明没有错误,我传递了一个允许数字的函数,其中允许字符串和数字的函数是允许的。
这似乎不是一个大问题,但是当您的类型是联合时,您会在不应该的情况下收到错误。这是一个例子,结果错误:
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));
“ICard”类型上不存在属性“cash”。
我知道,现在我必须执行以下操作,但是我无法在代码中表达现金和卡类型相互排斥:
interface IMix { cash?: number; cardtype?: string; cardnumber?: string; }
Typescript 关于第一个示例中的错误是正确的。考虑一下我们是否强制编译器接受修改后的函数:
所以 typescript 不允许这种行为的原因是它不能被证明对于任何具有签名
(val: number, i: number) => string
的函数都是正确的,而是取决于函数的具体实现。
现在在第二个示例中,该函数可以访问这些字段,并且不会出现运行时错误。这些字段可能未定义,但这对于此实现来说并不重要。我们可以做的是创建一个类型,其中联合中的所有可能字段都是可选的,这实际上是查看数组中项目的另一种方式(只是不是打字稿默认查看它的方式)。 Typescript 将允许我们传递带有这样的参数的函数,因为它是安全的,因为所有字段都是可选的,所以函数在使用它们之前都需要检查。
interface IMoney {
cash: number;
}
interface ICard {
cardtype: string;
cardnumber: string;
}
type IMix = IMoney | ICard;
const menu = [
{ cash: 566 },
{ cardtype: "credit", cardnumber: "111111111111111111" }
];
type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
type PartialUnion<T> = UnionToIntersection<T extends any ? Partial<T> : never>
menu.map((item: PartialUnion<IMix>, i: number) => (item.cash || item.cardtype));
请参阅
here了解
UnionToIntersection
T extends any ? Partial<T> : never
将获取联合中的每个成员(因为条件类型分布在联合上)并使其成为Partial
,这意味着所有字段现在都是可选的。然后我们使用
UnionToIntersection
将部分的并集转换为部分部分的交集。结果是一个类型,其中包含联合的每个成员中的所有字段,但所有字段都标记为部分字段。您似乎想要一个交集类型
可选映射 T 的每个属性并使它们成为可选
与接受的答案相比,这可能是实现相同结果的更简单方法