作者 | Matthew Miller

译者 | 弯月,责编 | 屠敏

出品 | CSDN(ID:CSDNnews)

以下为译文:

最近我在阅读 Asana 的博客时,看到了一篇关于 TypeScript 怪异行为的文章(https://blog.asana.com/2020/01/typescript-quirks/),文中提到的第一条 TypeScript 的怪异行为引起了我的兴趣。尽管看上去似乎前后不一致,但实际上这种类型系统的行为完全合乎逻辑。

该文章使用了接口 Dog 和函数 printDog 作为例子:

interface Dog {
  breed: string
} 

function printDog(dog: Dog) {
    console.log("Dog: " + dog.breed)
}

这段代码模拟了 TypeScript 中的一种流行写法。似乎到目前为止没什么问题,但这篇文章介绍了一个看似“前后不一致”的情况。尽管你可以把一个包含 breed 属性的对象先赋值给一个变量再传递给该函数,但你不能直接将这个对象传递给该函数。

const ginger = {
    breed: "Airedale",
    age: 3
};
printDog(ginger); //works

printDog({
    breed: "Airedale",
    age: 3
}); //fails

这是为什么?TypeScript 会检查对象中的额外属性,并发现bug,但为什么只有在直接将对象传递给函数时才会出问题?

这篇文章指出,TypeScirpt 是一个“结构化类型语言”,也就是说类型检查是根据对象的结构进行的,而不是根据它的继承关系进行的。但这条规则有一个例外,那就是当开发明确指定变量类型的时候。而且 TypeScript 函数的参数是协变的,这意味着它可以接受任何子类型。在结构化类型语言中,给已有类型添加一个属性就相当于扩展该类型。

那么,这个错误是为什么呢?如果它允许传递任何指定类型的子类型,那么为什么有时候会出错?

要回答这个问题,需要回到我之前提到的类型系统上。在创建一个变量并传递给函数时,变量会推断一个类型。在创建函数中的对象时,我们明确告诉 TypeScript 变量是 Dog 类型。创建变量时会检查类型是否包含多余属性,但函数调用时不会,因为函数调用是协变的。这个“不一致”与函数调用也没关系,只要在创建对象时指定类型就会产生同样的行为:

const ginger: Dog = {
    breed: "Airedale",
    age: 3
};

这段代码会产生与函数类型相同的错误,因为age并不是Dog类型的属性。

虽然类似的问题经常会困扰 TypeScript 开发者,但类型系统的任何行为通常都有合理的解释。如果没有,那你就应该向微软报告错误。

原文:https://matthewmiller.dev/blog/demystifying-typescript-quirk/

本文为 CSDN 翻译,转载请注明来源出处。

【End】

推荐阅读 

离你最近的疫情小区,终于可以自己查了!

5G 是否能让国产手机回到群雄割据时代?

蚂蚁金服AAAI收录论文曝光,动态网络剪枝方法、无语预训练的网络剪枝技术有重大突破

我是如何用6个月,从0编程经验变成数据科学家的?

孟岩:疫情带来的暂停,会让区块链与数字经济迎来更大反弹|算力大学视频公开课全文

2.7 亿学生宅家上课,家长有意见了......

你点的每一个在看,我认真当成了喜欢

猛戳“阅读原文”,填写中国远程办公-调查问卷

Logo

20年前,《新程序员》创刊时,我们的心愿是全面关注程序员成长,中国将拥有新一代世界级的程序员。20年后的今天,我们有了新的使命:助力中国IT技术人成长,成就一亿技术人!

更多推荐