TypeScript中类与接口

TypeScript中类与接口

自ES6开始,JavaScript中已经有了类,TypeScript中类存在的时间甚至更长。然而TypeScript中也有接口的概念,在代码中添加类型声明时,经常会出现这样的问题:

对于这种类型声明是使用接口还是使用类?

本文聚集TypeScript中接口和类概念比较,这样我们能很好地回答这个问题。

1.从示例开始

为了理解本文,下面先给一个示例:

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

这里只是示意很常见的一个任务————从远程服务器获取数据,然后进一步处理数据。

如何现在使用TypeScript处理上面代码,它会对response进行类型推断得到any类型。因为通过代码无法分析其应该属于何种类型。

为了增加程序类型安全,我们需要给response增加显示类型声明,请看下面代码告诉TypeScript编译器:

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

现在再回想前面提到的问题,新的Response应该被定义为interface还是class

2. 接口

TypeScript检查程序不同类型时,其中关键方法是使用“鸭子方法”。

如果看起来像鸭子,叫起来像鸭子,那就是一个鸭子

也就是说,我们决定什么能被类型化一种特定类型,主要看起是否有需要特性/结构/形状(后面就称为形状)。在TypeScript中,interface是用于给这种特定形状事物赋予名称的一种方法,后面在程序中可以通过名称引用它。

下面使用duck进行类比,使用接口进行定义:

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

有了Duck类型,我们在代码中可以其定义duck实例(通过实现Duck接口):

// 可以通过编译
const duck: Duck = {
    hasWings: true,
    noOfFeet: 2,
    quack() {
        console.log('Quack!')
    },
}

// 下面这句代码不能通过编译
const notADuck: Duck = {}
// The TypeScript compiler would tell us
// "Type '{}' is not assignable to type 'Duck'.
// Property 'hasWings' is missing in type '{}'."

接口可以帮助TypeScript在编译时捕获代码潜在问题,但有其还有更多重要特性:

接口仅用于编译时,编译后被即被删除,接口不会输出至最终的JavaScript代码中。

让我们通过接口来定义Response来完成本节:

interface Response {
    status: number // Some HTTP status code, such as 200
}

fetch('https://test.com/foo/bar')
    .then((response: Response) => {
        console.log(response.status)
    })

如果现在运行TypeScript编译器,不会有错误,当然环境中有fetch API,输出的JavaScript代码为:

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

我们看到编译时定义的类型没有影响运行时程序,这就是TypeScript神奇的接口功能!

3. 类

现在我们重新使用类定义Response:

class Response {
    status: number // Some HTTP status code, such as 200
}

fetch('https://test.com/foo/bar')
    .then((response: Response) => {
        console.log(response.status)
    })

我们仅把interface改为class,这时TypeScript编译没有错误,保证了类型安全,实现效果一样。但真正不同的是编译后的JavaScript代码。与interface不同,class也是JavaScript的结构体,但其包括更多信息。最大的差异是类提供行为的实现,不仅仅是形状属性。

下面我们看TypeScript编译后的代码:

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

差异是类被编译成ES5函数形式,但我们并不需要这些代码。如果开发大型应用,使用重复使用这种模式声明类型,会导致应用中增加大量额外代码。

4. 总结

如果创建类型描述API的返回值,使用接口比较合适。与类不同,接口在编译后被完全删除,不会在JavaScript中增加不必要的代码。如果以后需要对接口的实现进行扩展,很容易将其转换成完整的类。

发布了395 篇原创文章 · 获赞 761 · 访问量 143万+

猜你喜欢

转载自blog.csdn.net/neweastsun/article/details/103329237