如何解决打字稿对 Array.includes() 过于严格的问题

什么是修复以下代码且对可读性影响最小的干净方法?

操场

type Fruit = "apple" | "orange";
type Food = Fruit | "potato";

const fruits: Fruit[] = ["apple", "orange"];

function isFruit(thing: Food) {
  return fruits.includes(thing); // "potato" is not assignable to type 'Fruit'.
}

回答

首先,请阅读 TypeScript 3.x 天的 QA,其中有人问了与您基本相同的问题:TypeScript const assertions: how to use Array.prototype.includes?

现在,在您的情况下,作为@CertainPerformance 建议unknown[](丢失类型信息)的替代方案,您可以合法地扩大fruitsreadonly string[](不使用as),它与Fruit和兼容Food

type Fruit = "apple" | "orange";
type Food = Fruit | "potato" | "egg";
const fruits: readonly Fruit[] = ["apple", "orange"];
function isFruit(food: Food): food is Fruit {
const fruitsAsStrings: readonly string[] = fruits;
return fruitsAsStrings.includes(food);
}

另一种(理论上更“正确”)的方法是向接口添加一个变体 includes成员ReadonlyArray<T>(如链接的 QA 中所建议的那样),它允许U成为 ofT而不是相反的超类型。

interface ReadonlyArray<T> {
includes<U>(x: U & ((T & U) extends never ? never : unknown)): boolean;
}
type Fruit = "apple" | "orange";
type Food = Fruit | "potato" | "egg";
const fruits: readonly Fruit[] = ["apple", "orange"];
function isFruit(food: Food): food is Fruit {
return fruits.includes(food);
}

说了这么多......如果你打算使用集合类型作为值/类型集成员资格测试,你应该使用 JavaScriptobject而不是数组:不仅是因为性能原因(因为object键查找是O(1)数组includesis O(n),但也因为 TypeScript 对keyof类型更有效。

...实现这是读者的练习。


以上是如何解决打字稿对 Array.includes() 过于严格的问题的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>