详解 TypyScript 的一个怪异行为

  1. 云栖社区>
  2. 云栖号资讯>
  3. 博客>
  4. 正文

详解 TypyScript 的一个怪异行为

云栖号资讯小编 2020-02-16 16:30:18 浏览324
展开阅读全文

云栖号:https://yqh.aliyun.com
第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策!

image

最近我在阅读 Asana 的博客时,看到了一篇关于 TypeScript 怪异行为的文章,文中提到的第一条 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://yqh.aliyun.com
第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策!

原文发布时间:2020-02-15
本文作者:Matthew Miller
本文来自:“CSDN公众号”,了解相关信息可以关注“CSDN

网友评论

登录后评论
0/500
评论