TypeScript Type Compatibility 类型兼容性

简介: TypeScript Type Compatibility 类型兼容性

官方链接

TypeScript 中的类型兼容性基于结构子类型。 结构类型是一种仅基于其成员关联类型的方法。这与 nominal typing 相反。考虑以下代码:

interface Pet {

 name: string;

}

class Dog {

 name: string;

}

let pet: Pet;

// OK, because of structural typing

pet = new Dog();

如果是 Java 或者 ABAP 编程语言,上述代码会出现编译错误,因为 Pet 类型 和 Dog 类型没有任何关联,虽然其正好都有一个类型为 string 的 name 字段。


在 C# 或 Java 等名义类型的语言中,上述代码将是错误的,因为 Dog 类没有明确地将自己描述为 Pet 接口的实现者。


TypeScript 的结构类型系统是根据 JavaScript 代码的典型编写方式设计的。 因为 JavaScript 广泛使用匿名对象,如函数表达式和对象字面量,所以用结构类型系统而不是名义类型系统来表示 JavaScript 库中发现的各种关系要自然得多。


什么是健全性 Soundness

TypeScript 的类型系统允许某些在编译时无法知道的操作是安全的。 当一个类型系统具有这个属性时,它就被认为不是“健全的”。 仔细考虑了 TypeScript 允许不良行为的地方,在整个文档中,我们将解释这些地方发生的地方以及它们背后的激励场景。


TypeScript 结构类型系统的基本规则是,如果 y 至少具有与 x 相同的成员,则 x 与 y 兼容。 例如,考虑以下代码,其中包含一个名为 Pet 的接口,该接口具有 name 属性。这段代码是合法的:

interface Pet {

 name: string;

}

let pet: Pet;

// dog's inferred type is { name: string; owner: string; }

let dog = { name: "Lassie", owner: "Rudd Weatherwax" };

pet = dog;

为了检查 dog 是否可以分配给 pet,编译器会检查 pet 的每个属性,以在 dog 中找到对应的兼容属性。 在这种情况下, dog 必须有一个名为 name 的成员,它是一个字符串。 确实如此,因此允许分配。

同理,下列代码也合法:

interface Pet {

 name: string;

}

let dog = { name: "Lassie", owner: "Rudd Weatherwax" };

function greet(pet: Pet) {

 console.log("Hello, " + pet.name);

}

greet(dog); // OK

请注意 dog 有一个额外的 owner 属性,但这不会产生错误。 检查兼容性时只考虑目标类型的成员(在本例中为 Pet)。


如何判断两个函数类型是否兼容

虽然比较原始类型和对象类型相对简单,但哪些类型的函数应该被视为兼容的问题更复杂一些。 让我们从两个仅参数列表不同的函数的基本示例开始

let x = (a: number) => 0;

let y = (b: number, s: string) => 0;

y = x; // OK

x = y; // Error

请注意 dog 有一个额外的 owner 属性,但这不会产生错误。 检查兼容性时只考虑目标类型的成员(在本例中为 Pet)。


如何判断两个函数类型是否兼容

虽然比较原始类型和对象类型相对简单,但哪些类型的函数应该被视为兼容的问题更复杂一些。 让我们从两个仅参数列表不同的函数的基本示例开始:

let x = (a: number) => 0;

let y = (b: number, s: string) => 0;

y = x; // OK

x = y; // Error

要检查 x 是否可分配给 y,我们首先查看参数列表。 x 中的每个参数都必须在 y 中有一个对应类型的兼容参数。 请注意,不考虑参数的名称,只考虑它们的类型。 在这种情况下,x 的每个参数在 y 中都有一个对应的兼容参数,因此允许赋值。


第二个赋值是错误的,因为 y 有一个 x 没有的必需的第二个参数,所以不允许赋值。


您可能想知道为什么我们允许像示例 y = x 中那样“丢弃”参数。 允许这种赋值的原因是忽略额外的函数参数在 JavaScript 中实际上很常见。 例如,Array#forEach 为回调函数提供了三个参数:数组元素、其索引和包含的数组。 尽管如此,提供一个只使用第一个参数的回调是非常有用的:

let items = [1, 2, 3];

// Don't force these extra parameters

items.forEach((item, index, array) => console.log(item));

// Should be OK!

items.forEach((item) => console.log(item));

再来看如果两个函数的返回类型不完全一致,兼容性又将如何处理。

let x = () => ({ name: "Alice" });

let y = () => ({ name: "Alice", location: "Seattle" });

x = y; // OK

y = x; // Error, because x() lacks a location property

Function Parameter Bivariance

相关文章
|
2天前
|
JavaScript 前端开发 索引
TypeScript 的数组类型
TypeScript 的数组类型
13 1
|
2天前
|
JavaScript 安全
TypeScript(十一)泛型工具类型
TypeScript(十一)泛型工具类型
|
2天前
|
JavaScript 前端开发 编译器
TypeScript(五)类型别名及类型符号
TypeScript(五)类型别名及类型符号
|
2天前
|
JavaScript 前端开发
TypeScript(二)基本类型和特殊类型
TypeScript(二)基本类型和特殊类型
|
7天前
|
JavaScript 安全 开发者
Vue3 中更好地利用 TypeScript 的类型系统来提高代码质量
Vue3 中更好地利用 TypeScript 的类型系统来提高代码质量
|
29天前
|
JavaScript 前端开发 Java
TypeScript 类型兼容性
TypeScript 类型兼容性
|
29天前
|
JavaScript 前端开发
typescript 混合类型
typescript 混合类型
|
13天前
|
JavaScript 前端开发 IDE
TypeScript中的声明文件(.d.ts):扩展类型系统
TypeScript的`.d.ts`声明文件为JS库提供类型信息,增强IDE支持,如自动完成和类型检查。通过声明合并,可在全局作用域定义类型。示例包括为`my-library`创建声明模块,导出函数和接口。声明文件通常存于`@types`或指定`typeRoots`。用于旧JS代码的类型注解,如`myGlobalObject`。学习更多,参阅TypeScript官方文档。分享你的TS声明文件经验!
|
25天前
|
JavaScript 前端开发 安全
TypeScript:静态类型的动态语言
【6月更文挑战第9天】TypeScript是JavaScript的静态类型超集,解决JS类型安全问题,提供更强的代码组织和维护。它引入静态类型、接口和类,增强类型安全,减少运行时错误。TS与JS无缝集成,兼容现有库和框架,拥有丰富的开发工具和活跃社区。广泛应用在各种规模项目中,尤其提升复杂前端应用的代码质量。学习TypeScript对提升开发效率和代码可靠性极具价值。
28 10
|
24天前
|
前端开发 JavaScript 安全
TypeScript作为一种静态类型的JavaScript超集,其强大的类型系统和面向对象编程特性为微前端架构的实现提供了有力的支持
【6月更文挑战第11天】微前端架构借助TypeScript提升开发效率和代码可靠性。 TypeScript提供类型安全,防止微前端间通信出错;智能提示和自动补全加速跨代码库开发;重构支持简化代码更新。通过定义公共接口确保一致性,用TypeScript编写微前端以保证质量。集成到构建流程确保顺利构建打包。在微前端场景中,TypeScript是强有力的语言选择。
32 2