美文网首页我爱编程
TypeScript: Classes 和 Interfaces

TypeScript: Classes 和 Interfaces

作者: b2cc56969e2e | 来源:发表于2017-05-04 14:53 被阅读5164次
    By James Henry on January 12, 2017

    我们已经在Javascript中接触了class这个概念,在TypeScript中也有更广泛的使用。在TypeScript中,也存在另外一类类似的用法叫做interface,这样问题就来了:

    在变量声明中,classinterface这两种究竟该使用哪个?

    这篇文章就是解答上面这个问题的。

    一个例子

    为了理解这个概念,我们先从一个例子开始:

    fetch('https://jameshenry.blog/foo/bar')
        .then((response) => {
            console.log(response.status) // Some HTTP status code, such as 200
        })
    

    这是一个从服务器中调用数据到前端的代码。

    如果使用TypeScript执行这段代码,其中的response会被强制转化为any类型,这是毋容置疑的,因为没有任何信息指示response的类型。

    如果我们要限定response的类型,这样使程序更加安全可控,我们可以这样指定response

    // `Response` will be defined here...
    
    fetch('https://jameshenry.blog/foo/bar')
        .then((response: Response) => {
            console.log(response.status)
        })
    

    现在我们到了问题的核心点了,究竟我们应该使用class还是interface作为response的类型?

    interface是什么

    TypeScript检查变量类型的时候,判断一个类型的一个关键方法就是“鸭子类型判断法”。

    "如果看起来是鸭子,叫声也像鸭子,那么它就是鸭子。"

    换句话说,使用特定的结构、形状或者特征来分类。

    在TypeScript中,interface就是这么一种归类方法,我们可以为这种类型命名,这样在之后的程序中使用。

    我们使用鸭子类型判断法来制作一个interface

    // A duck must have...
    interface Duck {
        // ...a `hasWings` property with the value `true` (boolean literal type)
        hasWings: true
        // ...a `noOfFeet` property with the value `2` (number literal type)
        noOfFeet: 2
        // ...a `quack` method which does not return anything
        quack(): void
    }
    

    现在在TypeScript中,如果我们要指定一个类型是鸭子类型,我们要做的就是标注他的类型是Duck

    // This would pass type-checking!
    const duck: Duck = {
        hasWings: true,
        noOfFeet: 2,
        quack() {
            console.log('Quack!')
        },
    }
    
    // This would not pass type-checking as it does not
    // correctly implement the Duck interface.
    const notADuck: Duck = {}
    // The TypeScript compiler would tell us
    // "Type '{}' is not assignable to type 'Duck'.
    // Property 'hasWings' is missing in type '{}'."
    

    这样我们可以在TypeScript中,通过指定类型来可以提前发现程序可能存在的问题,还有一个细节需要我们记住:

    interface只是用在TypeScript编译的时候,编译完成后就会删除。不会在编译完成后的JavaScript文件中存在。

    让我们来完成之前Responseinterface类型:

    interface Response {
        status: number // Some HTTP status code, such as 200
    }
    
    fetch('https://jameshenry.blog/foo/bar')
        .then((response: Response) => {
            console.log(response.status)
        })
    

    使用TypeScript编译,没有错误发生,编译后的JavaScript文件如下:

    fetch('https://jameshenry.blog/foo/bar')
        .then(function (response) {
        console.log(response.status);
    });
    

    编译期间会有关于类型信息的内容,如果有错误会及时提醒,而一旦编译完成,JavaScript文件不会有关于类型信息的内容。

    使用Class

    如果我们使用class 代替interface作为Response的类型:

    class Response {
        status: number // Some HTTP status code, such as 200
    }
    
    fetch('https://jameshenry.blog/foo/bar')
        .then((response: Response) => {
            console.log(response.status)
        })
    

    我们只是简单的替换了interface,编译的时候也没有提醒错误,结果也是一样的。

    真正的不同之处是编译之后的JavaScript文件

    不像interfaceclass同样也是JavaScript的变量类型,所以这里不仅仅是改变了名称。

    classinterface最大的不同在于class还提供了其他内容的实现方法,而不仅仅是形状内容

    这是替换为class之后的编译后的JavaScript文件:

    var Response = (function () {
        function Response() {
        }
        return Response;
    }());
    fetch('https://jameshenry.blog/foo/bar')
        .then(function (response) {
        console.log(response.status);
    });
    

    发生了巨大的改变!我们看到,class已经转化为ES5类型,现在看来是一个毫无意义的JavaScript代码。但是如果我们有一个大型的程序,需要不断调用classes作为类型声明,那么这个class中就要填充很多的内容了。

    总结和延伸

    如果新建一个从服务器或类似的模型数据,最好使用interface

    不像classesinterface会在编译之后完全删除。

    如果我们会在之后会多次调整使用同一个interface,那么我们最好将其转化成class来使用。

    以后,我们可以关注abstractclass,implements关键字可以同时实现interface和class。

    相关文章

      网友评论

        本文标题:TypeScript: Classes 和 Interfaces

        本文链接:https://www.haomeiwen.com/subject/wpzrtxtx.html