Typescript:勾选";“类型”;针对自定义类型

Typescript:勾选";“类型”;针对自定义类型,typescript,types,Typescript,Types,比如说,我有一个自定义类型 export type Fruit = "apple" | "banana" | "grape"; 我想确定字符串是否是水果类型的一部分。我怎样才能做到这一点 下面的方法不起作用 let myfruit = "pear"; if (typeof myfruit === "Fruit") { console.log("My fruit is of type 'Fruit'"); } 任何想法都很感激 您可能会对TypeScript中的值和类型之间的差异感到困

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

export type Fruit = "apple" | "banana" | "grape";
我想确定字符串是否是水果类型的一部分。我怎样才能做到这一点

下面的方法不起作用

let myfruit = "pear";
if (typeof myfruit === "Fruit") {
    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=TypeofBar
将进入JavaScript,它将在运行时使用并生成一个字符串。但是
type-TypeofBar=条的类型
;将被擦除,并使用检查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”
;它永远不会是
水果
水果
。您无法在运行时获得TypeScript类型查询运算符的结果,因为类型系统在运行时被擦除。您需要放弃
类型的
运算符


您可以做的是对照三个已知的
Fruit
字符串文本检查
myfruit
的值。。。例如,这是:

let myfruit = "pear";
if (myfruit === "apple" || myfruit === "banana" || myfruit === "grape") {
  console.log("My fruit is of type 'Fruit'");
}
完美,对吧?好吧,也许这看起来有很多多余的代码。这里有一个不那么多余的方法。首先,根据现有的文本值数组定义
水果
类型。。。TypeScript可以从值推断类型,但不能从类型生成值

const fruit = ["apple", "banana", "grape"] as const;
export type Fruit = (typeof fruit)[number];
您可以验证
水果
的类型是否与您手动定义的类型相同。然后,对于类型测试,您可以使用如下方法:

const isFruit = (x: any): x is Fruit => fruit.includes(x);
isFruit()。让我们看看它的工作:

let myfruit = "pear";
if (isFruit(myfruit)) {
  console.log("My fruit is of type 'Fruit'");
}
该类型保护还让编译器知道,在
if
语句的“then”子句中,
myfruit
Fruit
。想象一下,如果您有一个函数只接受
结果
,而一个值可能是也可能不是
结果

declare function acceptFruit(f: Fruit): void;
const myfruit = Math.random() < 0.5 ? "pear" : "banana";
但检查后,您可以在“then”子句中调用它:

if (isFruit(myfruit)) {
  acceptFruit(myfruit); // okay, myfruit is known to be "banana"
}
这大概就是为什么要首先检查自定义类型。这样你就可以做了


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


哇,回答得太好了,谢谢!我唯一需要更改的是
constisfruit=(x:any):x是Fruit=>Fruit.includes(x)-我必须编写
水果索引(x)!=-1
。否则,我会收到以下错误:
Property“includes”在类型上不存在…
这一定是我读过的最有趣、信息最丰富的S/O答案之一。谢谢这确实是一个很棒的帖子。然而,我很难理解这个线型水果=(水果类型)[number];水果的类型是
typeoffruit
Array
,因此
ruit
相当于
(Array)[number]
。语法
T[K]
表示
T
的属性类型,其键类型为
K
。因此
(Array)[number]
表示“其键为
number
类型的
数组的属性类型”,或:“数组的数组元素”
,或:
苹果“|”香蕉“|”葡萄“
。惊人的解释。官方文件中有这样的内容吗?我特别惊讶于这句话:
export-type-Fruit=(typeof-Fruit)[number]
。怎么会有人想到这个???
if (isFruit(myfruit)) {
  acceptFruit(myfruit); // okay, myfruit is known to be "banana"
}