简答:
您不能在运行时使用typeof 来检查仅在编译时存在的interface 类型。相反,您可以编写 user-defined type guard function 来检查此类类型:
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 添加了一个静态类型系统,that type system gets erased when the code is transpiled。 TypeScript 的语法是这样的:一些表达式和语句引用运行时存在的 values,而其他表达式和语句引用仅在设计/编译时存在的 types。值有类型,但它们本身不是类型。重要的是,在代码中的某些地方,编译器会期望一个值并将它找到的表达式解释为一个值,如果可能的话,编译器会期望一个类型并将它找到的表达式解释为一个类型。
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 operator 并生成一个字符串。但是type TypeofBar = typeof bar;被擦除,它正在使用 TypeScript type query operator 来检查 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";它永远不会是Fruit 或"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 是否与您手动定义的类型相同。然后,对于类型测试,您可以像这样使用user-defined type guard:
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 的函数,以及一个可能是也可能不是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。您可以与字符串进行比较。您可以进行一些类型推断和类型保护来消除重复代码并从编译器获取控制流类型分析。
Playground link to code