TypeScript: Classes 和 Interfaces

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)