打字稿:对照自定义类型检查“ typeof”

迈亚:

我有一个自定义类型,比方说

export type Fruit = "apple" | "banana" | "grape";

我想确定一个字符串是否是Fruit类型的一部分。我该怎么做?

以下无效。

let myfruit = "pear";
if (typeof myfruit === "Fruit") {
    console.log("My fruit is of type 'Fruit'");
}

任何想法表示赞赏!

jcalz:

您可能对TypeScript中的值和类型之间的差异感到困惑,特别是因为它与typeof运算符有关。您可能已经知道,TypeScript在JavaScript中添加了一个静态类型系统,并且在代码被编译时会擦除该类型系统TypeScript的语法使得某些表达式和语句引用在运行时存在的,而其他表达式和语句引用仅在设计/编译时存在的类型类型,但它们本身不是类型。重要的是,在代码中的某些地方,编译器将期望一个值并在可能的情况下将其找到的表达式解释为一个值,在其他地方,编译器将期望一个类型并在可能的情况下将其找到的表达式解释为一个类型。

typeof运营商过着双重的生活。表达式typeof x始终期望x是一个值,但typeof x取决于上下文,它本身可以是值或类型:

let bar = {a: 0};
let TypeofBar = typeof bar; // the value "object"
type TypeofBar = typeof bar; // the type {a: number}

该行将let TypeofBar = typeof bar;通过JavaScript,并在运行时使用JavaScript typeof运算符并生成一个字符串。但是type TypeofBar = typeof bar; 会被擦除,并使用TypeScript类型查询运算符检查TypeScript已分配给名为的值的静态类型bar

在您的代码中

let myfruit = "pear";
if (typeof myfruit === "Fruit") { // "string" === "Fruit" ?!
    console.log("My fruit is of type 'Fruit'");
}

typeof myfruit是值,而不是类型。因此,它是JavaScript typeof运算符,而不是TypeScript类型查询运算符。它总是返回值"string"; 它永远不会Fruit"Fruit"您无法在运行时获取TypeScript类型查询运算符的结果,因为在运行时会擦除类型系统。您需要放弃typeof运营商。


可以myfruit根据三个已知的Fruit字符串文字检查的值...例如,如下所示:

let myfruit = "pear";
if (myfruit === "apple" || myfruit === "banana" || myfruit === "grape") {
  console.log("My fruit is of type 'Fruit'");
}

完美吧?好吧,也许这似乎是很多冗余代码。这是一种不太冗余的方法。首先,Fruit根据现有的文字值数组定义类型... TypeScript可以从值中推断类型,但不能从类型中生成值。

const stringLitArray = <L extends string>(arr: L[]) => arr;
const fruit = stringLitArray(["apple", "banana", "grape"]);
export type Fruit = (typeof fruit)[number];

您可以验证该Fruit类型与您手动定义的类型相同。然后,对于类型测试,您可以使用用户定义的类型保护,如下所示:

const isFruit = (x: any): x is Fruit => fruit.includes(x);

isFruit()是一个函数,该函数检查是否在fruit数组中找到其参数,如果是,则将其参数的类型缩小为Fruit让我们看看它的工作原理:

let myfruit = "pear";
if (isFruit(myfruit)) {
  console.log("My fruit is of type 'Fruit'");
}

该类型防护还使编译器知道该if语句的“ then”子句中的myfruit一个Fruit想象一下,如果您有一个仅接受的函数Fruit,并且一个值可能是也可能不是Fruit

declare function acceptFruit(f: Fruit): void;
const myfruit = Math.random() < 0.5 ? "pear" : "banana";

您不能直接调用该函数:

acceptFruit(myfruit); // error, myfruit might be "pear"

但是您可以在检查之后在“ then”子句中调用它:

if (isFruit(myfruit)) {
  acceptFruit(myfruit); // okay, myfruit is known to be "banana"
}

大概就是为什么要首先检查自定义类型的原因。这样就可以做到这一点。


回顾一下:您不能使用typeof您可以与字符串进行比较。您可以进行一些类型推断和类型防护,以消除重复的代码并从编译器获取控制流类型分析。

希望能有所帮助。祝好运。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章