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
Typescript: Check "typeof" against custom type
提问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 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 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 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:
该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 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.
typeof myfruit
是一个值,而不是一个类型。所以它是 JavaScripttypeof
运算符,而不是 TypeScript 类型查询运算符。它将始终返回值"string"
;它永远不会是Fruit
或"Fruit"
。您无法在运行时获取 TypeScript 类型查询运算符的结果,因为类型系统在运行时已被擦除。你需要放弃typeof
运营商。
What you cando is check the value of myfruit
against the three known Fruit
string 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 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.
完美,对吧?好吧,也许这看起来像是很多多余的代码。这是一种不那么多余的方法。首先,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 Fruit
is 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 fruit
array, 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 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
:
该类型保护还让编译器知道在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.
希望有帮助。祝你好运。