打字稿:检查“typeof"反对自定义类型 [英] Typescript: Check "typeof" against custom type

查看:29
本文介绍了打字稿:检查“typeof"反对自定义类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a custom type, let's say

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

我想确定一个字符串是否属于 Fruit 类型.我怎样才能做到这一点?

I would like to determine if a string is part of the Fruit type. How can I accomplish this?

以下不起作用.

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

任何想法表示赞赏!

推荐答案

简答:

您不能在运行时使用 typeof 来检查 interface 类型,它只存在于编译时.相反,您可以编写一个用户定义的类型保护函数 检查此类类型:

You can't use typeof at runtime to check for interface types, which only exist at compile time. Instead you can write a user-defined type guard function to check for such types:

const fruit = ["apple", "banana", "grape"] as const;
type Fruit = (typeof fruit)[number];
const isFruit = (x: any): x is Fruit => fruit.includes(x);

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

长答案如下:

您可能对 TypeScript 中值和类型之间的区别感到困惑,尤其是当它与 typeof 运算符相关时.您可能知道,TypeScript 为 JavaScript 添加了一个静态类型系统,并且 当代码被转译时,该类型系统被删除.TypeScript 的语法是这样的,一些表达式和语句引用在运行时存在的,而其他表达式和语句引用仅在设计/编译时存在的类型.值类型,但它们本身不是类型.重要的是,在代码中有些地方编译器会期望一个值并在可能的情况下将它找到的表达式解释为一个值,而在其他地方编译器将期望一个类型并将它找到的表达式解释为一个类型(如果可能).

You might be confused about the difference between values and types in TypeScript, especially as it relates to the typeof operator. As you may be aware, TypeScript adds a static type system to JavaScript, and that type system gets erased when the code is transpiled. The syntax of TypeScript is such that some expressions and statements refer to values that exist at runtime, while other expressions and statements refer to types that exist only at design/compile time. Values have types, but they are not types themselves. Importantly, there are some places in the code where the compiler will expect a value and interpret the expression it finds as a value if possible, and other places where the compiler will expect a type and interpret the expression it finds as a type if possible.

typeof 运算符带来双重生活.表达式 typeof x 总是期望 x 是一个值,但 typeof x 本身可以是一个值或类型,具体取决于上下文:

The typeof operator leads a double life. The expression typeof x always expects x to be a value, but typeof x itself could be a value or type depending on the context:

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 operator 在运行时生成一个字符串.但是type TypeofBar = typeof bar;被删除,它使用 TypeScript 类型查询运算符来检查 TypeScript 分配给名为 bar 的值的静态类型.

The line let TypeofBar = typeof bar; will make it through to the JavaScript, and it will use the JavaScript typeof operator at runtime and produce a string. But type TypeofBar = typeof bar; is erased, and it is using the TypeScript type query operator to examine the static type that TypeScript has assigned to the value named bar.

在您的代码中,

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

typeof myfruit 是一个值,而不是一个类型.所以它是 JavaScript typeof 运算符,而不是 TypeScript 类型查询运算符.它将始终返回值 "string";它永远不会是 FruitFruit".您无法在运行时获取 TypeScript 类型查询运算符的结果,因为类型系统在运行时已被擦除.您需要放弃 typeof 运算符.

typeof myfruit is a value, not a type. So it's the JavaScript typeof operator, not the TypeScript type query operator. It will always return the value "string"; it will never be Fruit or "Fruit". You can't get the results of the TypeScript type query operator at runtime, because the type system is erased at runtime. You need to give up on the typeof operator.

可以做的是根据三个已知的 Fruit 字符串文字检查 myfruit 的值……例如,这个:

What you can do is check the value of myfruit against the three known Fruit string literals... like, for example, this:

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

完美,对吧?好吧,也许这看起来像是很多冗余代码.这是一种不那么多余的方法.首先,根据现有的文字值数组定义您的 Fruit 类型……TypeScript 可以从值推断类型,但不能从类型生成值.

Perfect, right? Okay, maybe that seems like a lot of redundant code. Here's a less redundant way to do it. First of all, define your Fruit type in terms of an existing array of literal values... TypeScript can infer types from values, but you can't generate values from types.

const fruit = ["apple", "banana", "grape"] as const;
export type Fruit = (typeof fruit)[number];

您可以验证 Fruit 是否与您手动定义的类型相同.然后,对于类型测试,您可以使用 用户定义的类型保护像这样:

You can verify that Fruit is the same type as you defined yourself manually. Then, for the type test, you can use a user-defined type guard like this:

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

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

isFruit() is a function which checks if its argument is found in the fruit array, and if so, narrows the type of its argument to Fruit. Let's see it work:

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

那个类型保护也让编译器知道在then"里面if 语句的子句,即 myfruitFruit.想象一下,如果你有一个只接受 Fruit 的函数,以及一个可能是也可能不是 Fruit 的值:

That type guard also lets the compiler know that inside the "then" clause of the if statement, that myfruit is a Fruit. Imagine if you had a function that only accepts Fruit, and a value that may or may not be a Fruit:

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

不能直接调用函数:

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

但是你可以在then"中调用它检查后的子句:

But you can call it inside the "then" clause after checking it:

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

这大概是您首先要检查自定义类型的原因.这样你就可以做到了.

Which is presumably why you want to check against your custom type in the first place. So that lets you do it.

总结:您不能使用 typeof.您可以与字符串进行比较.您可以进行一些类型推断和类型保护以消除重复代码并从编译器获得控制流类型分析.

To recap: you can't use typeof. You can compare against strings. You can do some type inference and a type guard to eliminate duplicated code and get control flow type analysis from the compiler.

游乐场连结代码

这篇关于打字稿:检查“typeof"反对自定义类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆