首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 重塑“类型思维”
02 | 类型基础(1):强类型与弱类型
03 | 类型基础(2):动态类型与静态类型
04 | 编写你的第一个TypeScript程序
05 | 基本类型
06 | 枚举类型
07 | 接口(1):对象类型接口
08 | 接口(2):函数类型接口
09 | 函数相关知识点梳理
10 | 类(1):继承和成员修饰符
11 | 类(2):抽象类与多态
12 | 类与接口的关系
13 | 泛型(1):泛型函数与泛型接口
14 | 泛型(2):泛型类与泛型约束
15 | 类型检查机制(1):类型推断
16 | 类型检查机制(2):类型兼容性
17 | 类型检查机制(3):类型保护
18 | 高级类型(1):交叉类型与联合类型
19 | 高级类型(2):索引类型
20 | 高级类型(3):映射类型
21 | 高级类型(4):条件类型
22 | ES6与CommonJS的模块系统
23 | 使用命名空间
24 | 理解声明合并
25 | 如何编写声明文件
26 | 配置tsconfig.json(1):文件选项
27 | 配置tsconfig.json(2):编译选项
28 | 配置tsconfig.json(3):工程引用
29 | 编译工具:从ts-loader到Babel
30 | 代码检查工具:从TSLint到ESLint
31 | 使用Jest进行单元测试
32 | 创建项目
33 | 组件与类型(1):函数组件与类组件
34 | 组件与类型(2):高阶组件与Hooks
35 | 事件处理与数据请求
36 | 列表渲染与路由
37 | Redux与类型
38 | 搭建服务端开发环境
39 | 列表的CRUD
40 | 导出Excel
41 | 搭建Vue开发环境
42 | 组件封装
43 | 组件发布
44 | 共存策略
45 | 宽松策略
46 | 严格策略
当前位置:
首页>>
技术小册>>
TypeScript开发实战
小册名称:TypeScript开发实战
### 16 | 类型检查机制(2):类型兼容性 在TypeScript中,类型兼容性是一个核心概念,它决定了在哪些情况下一个类型可以安全地赋值给另一个类型。理解类型兼容性对于编写既安全又灵活的TypeScript代码至关重要。本章将深入探讨TypeScript中的类型兼容性规则,包括基本类型兼容性、接口兼容性、枚举兼容性、泛型兼容性以及高级类型兼容性技巧。 #### 16.1 基本类型兼容性 TypeScript中的基本类型(如`number`、`string`、`boolean`、`void`、`null`、`undefined`、`any`、`never`和`unknown`)之间的兼容性遵循一系列直观但严格的规则。 - **数值与字符串不兼容**:`number`类型不能直接赋值给`string`类型,反之亦然。这是因为它们表示的数据类型本质不同。 - **布尔值与其他类型不兼容**:`boolean`类型与`number`、`string`等类型不兼容,因为布尔值用于逻辑判断,而数值和字符串用于表示数据。 - **`void`与`null`、`undefined`**:`void`类型表示没有任何类型返回的操作(如函数不返回任何值)。`void`类型可以赋值给`null`和`undefined`,但反过来不成立,因为`null`和`undefined`有更具体的含义。 - **`any`类型兼容性**:`any`类型可以赋值给任何类型,这是因为它表示任意类型。相反,任何类型也可以赋值给`any`类型,这使得`any`成为类型系统中的“通配符”。 - **`never`类型兼容性**:`never`类型表示的是那些永不存在的值的类型。它是所有类型的子类型,但没有任何类型可以是`never`的子类型(除了`never`本身)。这意味着你可以将`never`类型的值赋给任何类型,但反过来则不行。 - **`unknown`类型兼容性**:`unknown`类型表示未知类型的值。与`any`不同,`unknown`类型在赋值给其他类型之前必须进行显式类型断言或类型守卫,以确保类型安全。因此,`unknown`类型不能直接赋值给除`any`和`unknown`之外的其他类型,但其他类型可以赋值给`unknown`(尽管这在实际编程中很少见)。 #### 16.2 接口兼容性 接口之间的兼容性基于结构子类型化(Structural Subtyping)原则,即如果两个类型具有兼容的结构,则它们就是兼容的。这意味着,只要一个接口的所有成员在另一个接口中都能找到对应的成员(且类型兼容),那么这两个接口就是兼容的。 - **多余属性检查**:在TypeScript中,当尝试将一个对象字面量赋值给一个接口时,如果对象字面量包含接口中不存在的属性,TypeScript会报错,除非接口使用了额外的属性检查(通过索引签名或`[key: string]: any`等方式)。 - **可选属性与只读属性**:接口中的可选属性在赋值时可以不提供,而只读属性在赋值后不可修改。这些特性在类型兼容性判断中也会被考虑。 - **函数类型兼容性**:接口中的函数成员在类型兼容性判断时,遵循参数双向协变(bivariant)和返回类型逆变(contravariant)的规则。但请注意,从TypeScript 2.6开始,函数参数的协变性被限制在对比函数类型时,而在赋值操作中,参数类型必须是严格匹配的(即,参数类型必须是对比类型的子类型)。 #### 16.3 枚举兼容性 枚举类型在TypeScript中提供了一种表示一组命名常量的方式。枚举成员在类型兼容性方面,主要遵循其基础类型(默认为`number`)的规则。 - **枚举成员与基础类型**:枚举成员可以赋值给其基础类型的变量,反之亦然。但是,由于枚举成员具有特定的命名和值,直接进行这样的赋值可能会丢失上下文信息。 - **枚举类型之间的兼容性**:不同枚举类型之间默认是不兼容的,即使它们的成员值和结构完全相同。这是因为枚举类型在TypeScript中不仅仅是值的集合,还包含了命名和可能的类型安全特性。 #### 16.4 泛型兼容性 泛型为TypeScript提供了编写可重用组件的能力,同时保持类型安全。泛型类型之间的兼容性取决于其类型参数的兼容性。 - **泛型类型参数**:当比较两个泛型类型时,TypeScript会尝试找到一种方式,使得这两个类型在某种类型参数替换下变得兼容。这通常涉及到类型参数的推断和约束。 - **泛型约束**:通过为泛型类型参数添加约束(如接口或类),可以限制类型参数的可能类型,从而影响泛型类型的兼容性。 - **高级泛型技巧**:如条件类型、映射类型等,为泛型类型兼容性提供了更复杂的表达方式。这些技巧允许开发者根据类型参数的不同情况,动态地改变类型结构。 #### 16.5 高级类型兼容性技巧 - **类型断言**:当TypeScript的类型推断无法满足需求时,可以使用类型断言来明确指定一个值的类型。但请注意,类型断言会绕过TypeScript的类型检查,因此应谨慎使用。 - **类型守卫**:类型守卫是一种更安全的替代类型断言的方法,它通过运行时检查来确保类型安全。类型守卫可以是函数也可以是类型谓词(type predicates)。 - **交叉类型与联合类型**:交叉类型(Intersection Types)表示一个对象同时是多个类型的实例,而联合类型(Union Types)表示一个对象可以是多个类型中的任何一个。在类型兼容性判断中,交叉类型和联合类型都有其特定的规则。 - **高级类型操作**:如条件类型(Conditional Types)、映射类型(Mapped Types)等,为TypeScript的类型系统提供了强大的表达能力,同时也为类型兼容性判断带来了更多的复杂性。 ### 结语 类型兼容性是TypeScript类型检查机制的重要组成部分,它确保了类型安全的同时,也提供了足够的灵活性以适应不同的编程需求。通过深入理解基本类型兼容性、接口兼容性、枚举兼容性、泛型兼容性以及高级类型兼容性技巧,开发者可以编写出既安全又高效的TypeScript代码。希望本章内容能为你的TypeScript开发实战之旅提供有力的支持。
上一篇:
15 | 类型检查机制(1):类型推断
下一篇:
17 | 类型检查机制(3):类型保护
该分类下的相关小册推荐:
TypeScript 全面进阶指南
TypeScript入门指南
剑指TypeScript