By James Henry on January 12, 2017
我们已经在Javascript中接触了class
这个概念,在TypeScript中也有更广泛的使用。在TypeScript中,也存在另外一类类似的用法叫做interface
,这样问题就来了:
在变量声明中,
class
和interface
这两种究竟该使用哪个?
这篇文章就是解答上面这个问题的。
一个例子
为了理解这个概念,我们先从一个例子开始:
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文件中存在。
让我们来完成之前Response
的interface
类型:
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文件
不像interface
,class
同样也是JavaScript的变量类型,所以这里不仅仅是改变了名称。
class
和interface
最大的不同在于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
。
不像classes
,interface
会在编译之后完全删除。
如果我们会在之后会多次调整使用同一个interface
,那么我们最好将其转化成class
来使用。
以后,我们可以关注abstract
class,implements
关键字可以同时实现interface和class。
网友评论