ChatGPT解决这个技术问题 Extra ChatGPT

打字稿中的`is`关键字有什么作用?

我遇到了一些看起来像这样的代码:

export function foo(arg: string): arg is MyType {
    return ...
}

我无法在 docs 或 google 中搜索 is,这是一个非常常见的词,并且基本上出现在每个页面上。

关键字在这种情况下有什么作用?


M
Md_Zubair Ahmed

有关详细信息,请参阅 user-defined type guard functions 的参考。

function isString(test: any): test is string{
    return typeof test === "string";
}

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length); // string function
    }
}
example("hello world");

使用上述格式的类型谓词 test is string(而不是只使用 boolean 作为返回类型),在调用 isString() 后,如果函数返回 trueTypeScript 会将类型缩小为 { 5} 在任何由函数调用保护的块中。 编译器会认为 foo 在下面保护的块中是 string(并且仅在下面保护的块中)

{
    console.log("it is a string" + foo);
    console.log(foo.length); // string function
}

类型谓词仅在编译时使用。生成的 .js 文件(运行时)没有区别,因为它不考虑 TYPE。

我将在以下四个示例中说明差异。

例如 1:上面的示例代码不会有编译错误,也不会出现运行时错误。

例如 2:下面的示例代码将出现编译错误(以及运行时错误),因为 TypeScript 已将类型缩小到 string 并检查 toExponential 不属于 string 方法。

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
        console.log(foo.toExponential(2));
    }
}

例如 3:下面的示例代码没有编译错误,但会出现运行时错误,因为 TypeScript 只会在受保护的块中将类型缩小到 string 而不是在之后,因此 foo.toExponential 不会产生编译错误(TypeScript 会不认为它是 string 类型)。但是,在运行时,string 没有 toExponential 方法,因此会出现运行时错误。

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
    }
    console.log(foo.toExponential(2));
}

例 4:如果我们不使用 test is string(类型谓词),TypeScript 不会缩小受保护块中的类型,下面的示例代码不会出现编译错误,但会出现运行时错误。

function isString(test: any): boolean{
    return typeof test === "string";
}
function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
        console.log(foo.toExponential(2));
    }
}

结论是 test is string(类型谓词)在编译时用于告诉开发人员代码将有机会出现运行时错误。对于 javascript,开发人员不会知道编译时的错误。这就是使用 TypeScript 的优势。


B
Bruno Grieder

我知道的唯一用途是您的示例:在用户定义的类型保护中指定“类型谓词”(arg is MyType

请参阅此 reference 中的用户定义类型保护

这是另一个reference


我也在文档中看到了这一点,多么奇怪的设计决定,这种情况完全可以通过返回类型 boolean 来处理,对吧?
@benjaminz这可能需要对SO提出自己的问题,但我可以向您展示一个快速示例,说明它们有何不同。 is 关键字实际上是在转换类型,并且可以在稍后的代码中捕获类型错误。有关详细信息,请参阅 this example
@benjaminz 我看不出如何用布尔值处理它。 Typescript 需要知道传递对象的函数的功能类似于类型保护。如果它只是返回类型 true 或 false,那么 Typescript 怎么知道它确实是一个类型保护,而不仅仅是某个在对象为真时返回 true 的任意函数。它如何知道缩小对象的类型?其次,它如何知道将对象的类型缩小到什么类型?如果参数是三种类型之一怎么办?它需要知道 true 对应于特定类型。
好吧,也许返回布尔值不起作用,但为什么不实现'is'运算符呢?我们可以只写 if (pet is Fish){fish.swim()},而不是写 function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined; }; if (isFish(pet)){fish.swim()}
另一方面,从 OOP 的角度来看,类型保护是不好的。所以,对于那些想要进行疯狂类型转换的人来说,也许这个样板是稻草人。如果你想检查一个变量类型,你可能应该修改你的架构。如果你仍然想要类型检查,也许你应该受苦:)