typescript 打字稿:根据自定义类型检查“typeof”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51528780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:56:40  来源:igfitidea点击:

Typescript: Check "typeof" against custom type

typescripttypes

提问by maia

I have a custom type, let's say

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

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

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

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

The following doesn't work.

以下不起作用。

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

Any thoughts appreciated!

任何想法表示赞赏!

回答by jcalz

You might be confused about the difference between values and types in TypeScript, especially as it relates to the typeofoperator. 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 valuesthat exist at runtime, while other expressions and statements refer to typesthat exist only at design/compile time. Values havetypes, 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.

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

The typeofoperator leads a double life. The expression typeof xalways expects xto be a value, but typeof xitself could be a value or type depending on the context:

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}

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

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

In your code,

在您的代码中,

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

typeof myfruitis a value, not a type. So it's the JavaScript typeofoperator, not the TypeScript type query operator. It will always return the value "string"; it will never be Fruitor "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 typeofoperator.

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



What you cando is check the value of myfruitagainst the three known Fruitstring literals... like, for example, this:

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

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

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 Fruittype in terms of an existing array of literal values... TypeScript can infer types from values, but you can't generate values from types.

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

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

You can verify that Fruitis the same type as you defined yourself manually. Then, for the type test, you can use a user-defined type guardlike this:

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

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

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

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

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

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

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

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

You can't call the function directly:

您不能直接调用该函数:

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

But you cancall it inside the "then" clause after checking it:

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

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.

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



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. 您可以与字符串进行比较。您可以进行一些类型推断和类型保护以消除重复代码并从编译器获得控制流类型分析。

Hope that helps. Good luck.

希望有帮助。祝你好运。