为什么Typescript允许子类型化?

时间:2019-03-15 10:17:30

标签: typescript subtyping structural-typing

根据文档,“ TypeScript中的类型兼容性基于结构子类型”。所以这是可能的:

type Person: {
  name: string;
}

const developer = {
  name: 'Joe',
  language: 'Typescript',
}

// this is ok because Person is a subtype of typeof developer
const otherDeveloper: Person = developer; // who writes code like that?!

这会带来很多后果,其中之一就是使用Object.keys时会丢失类型信息:

// "keys" type is array of strings not `name` literal as this would be of course wrong because in runtime "keys" is ['name', 'language']
const keys = Object.keys(otherDeveloper); 

所以我试图在TS文档中按照他们的承诺找到这种子类型的原因,但是我找不到一个

  

我们仔细考虑了TypeScript允许不良行为发生的地方,在本文档中,我们将解释发生这些错误的地方以及背后的动机。

这可能对我有帮助的唯一地方是一个期望对象类型更窄的函数,例如:

function getName(person: Person) {
  return person.name;
}

getName(developer); // works fine because of subtyping

如果您必须在这种情况下使用强制转换,我个人认为没有什么大问题:

getName(developer as Person);

还有其他我可能会错过的例子吗?

1 个答案:

答案 0 :(得分:1)

Typescript使用结构化类型的原因是JS是鸭子类型。

因此,您可以执行上面在JS中编写的内容,理想情况下,您可以以更安全的类型在TS中进行操作。 Javascript不关心对象的声明类型,JS中没有这样的概念,它只关心对象在运行时具有的属性。因此,任何对象都可以传递到您的getName函数中,并且只要存在name属性,该函数就可以正常运行。

此外,由于JS的对象文字不属于特定类,因此很难在任何地方显式指定继承关系。使类型关系明确将使TS对JS开发人员的吸引力降低。在结构类型系统下,大多数类型都可以使用我们的类型,而不必非常明确地从中受益。

有一些方法可以通过使用私有属性(ex)或使用品牌类型(ex)来解决结构化类型并模仿打字稿中的规范类型