【问题标题】:What does the `is` keyword do in typescript?打字稿中的`is`关键字有什么作用?
【发布时间】:2017-02-26 03:20:01
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: typescript


    【解决方案1】:

    有关更多信息,请参阅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会缩小在由函数调用保护的任何块中键入string 编译器会认为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 的优势。

    【讨论】:

      【解决方案2】:

      我知道的唯一用途是您的示例:在用户定义的类型防护中指定“类型谓词”(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 的角度来看,类型保护是不好的。所以,对于那些想要进行疯狂类型转换的人来说,也许这个样板是稻草人。如果你想检查一个变量类型,你可能应该修改你的架构。如果你仍然想要类型检查,也许你应该受苦:)
      猜你喜欢
      • 2020-06-09
      • 2016-02-18
      • 1970-01-01
      • 2018-07-06
      • 1970-01-01
      • 2017-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多