typescript - 打字稿:根据自定义类型检查“typeof”
问题描述
我有一个自定义类型,比如说
export type Fruit = "apple" | "banana" | "grape";
我想确定一个字符串是否属于 Fruit 类型。我怎样才能做到这一点?
以下不起作用。
let myfruit = "pear";
if (typeof myfruit === "Fruit") {
console.log("My fruit is of type 'Fruit'");
}
任何想法表示赞赏!
解决方案
简短的回答:
您不能typeof
在运行时使用来检查interface
仅在编译时存在的类型。相反,您可以编写用户定义的类型保护函数来检查此类类型:
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 的语法是这样的,一些表达式和语句引用运行时存在的值,而其他表达式和语句引用仅在设计/编译时存在的类型。价值观有类型,但它们本身不是类型。重要的是,在代码中的某些地方,编译器会期望一个值并将它找到的表达式解释为一个值,如果可能的话,编译器会期望一个类型并将它找到的表达式解释为一个类型。
经营者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
是一个值,而不是一个类型。所以它是 JavaScripttypeof
运算符,而不是 TypeScript 类型查询运算符。它总是返回值"string"
;它永远不会是Fruit
or "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 fruit = ["apple", "banana", "grape"] as const;
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
,以及一个可能是也可能不是 a 的值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
. 您可以与字符串进行比较。您可以进行一些类型推断和类型保护,以消除重复代码并从编译器获取控制流类型分析。
推荐阅读
- asp.net-core - SharpApp 和 Office JS API
- java - 如何获取 SPARQL-DL 查询中使用的所有实体?
- python-3.7 - python条件格式替换
- postgresql - Postgres错误错误:右兄弟的左链接不匹配
- python - Python 对有序字典和生成的 .items() 迭代器进行排序
- azure - 名称中带有哈希的文件的 Web.config 规则
- python - flask_migrate BIGINT 列长度在 MySQL 中第一次被忽略
- nginx - nginx反向代理位置
- python - 有没有办法在重新采样的日期索引熊猫数据框中产生多个类别的计数?
- go - MarshalBinary time.Time:预测其字节大小