TypeScript类型兼容

先看个最简单的例子:接口赋值。TypeScript检查类型兼容性根本不关心具体类型名,只看结构是否匹配。比如你定义了一个Person接口,要求有name和age字段,这时候哪怕你拿一个Dog类型的对象过来,只要它恰好也有同名字段且类型匹配,TypeScript就会放行。这就是著名的"鸭子类型"------走起来像鸭子,叫起来像鸭子,那就是鸭子。

但这里有个细节要注意,源类型必须包含目标类型的所有必需属性。反过来就不行了:

函数兼容性就更有意思了。函数参数检查遵循"逆变"原则------听起来很玄乎,其实很简单:参数类型可以比定义的更宽泛,但不能更严格。比如下面这个例子:

为什么func2赋值给func1不行?因为func2定义时承诺能处理string和number,但func1只能处理number,如果把func2交给func1,碰到string参数就崩了。

返回值则相反,遵循"协变"------返回值类型必须更具体或完全相同:

数组和元组的兼容规则经常让人栽跟头。普通数组看类型参数是否兼容:

但元组就严格多了,必须长度和每个位置的类型都匹配:

枚举类型比较特殊,数字枚举和number互相兼容,但字符串枚举谁也不认:

类的兼容性规则有点反直觉。只比较实例成员,静态成员和构造函数不参与比较。而且private和protected成员会影响兼容性:

泛型兼容性最容易让人困惑。泛型本身不参与兼容性判断,最终看的是具体类型:

any类型在兼容性检查中是万能牌,但也很危险。unknown只能赋值给any和unknown自身,而never可以赋值给任何类型。

实际开发中,掌握这些规则能帮你避免很多奇怪的错误。特别是在使用第三方库时,经常需要自定义类型声明,理解兼容性规则就能写出更健壮的类型定义。记住TypeScript的类型系统是结构化的,这点和很多传统静态语言完全不同。

最后给个实用建议:当遇到复杂的类型兼容问题时,可以先把鼠标悬停在变量上查看推断出的类型,然后用类型断言临时绕过检查。但长期来说,还是应该理顺类型关系,毕竟类型安全的本质是为了减少运行时错误,而不是和编译器斗智斗勇。

相关推荐
一个懒人懒人8 小时前
Promise async/await与fetch的概念
前端·javascript·html
Mintopia8 小时前
Web 安全与反编译源码下的权限设计:构筑前后端一致的防护体系
前端·安全
输出输入8 小时前
前端核心技术
开发语言·前端
Mintopia8 小时前
Web 安全与反编译源码下的权限设计:构建前后端一体的信任防线
前端·安全·编译原理
林深现海9 小时前
Jetson Orin nano/nx刷机后无法打开chrome/firefox浏览器
前端·chrome·firefox
黄诂多9 小时前
APP原生与H5互调Bridge技术原理及基础使用
前端
前端市界9 小时前
用 React 手搓一个 3D 翻页书籍组件,呼吸海浪式翻页,交互体验带感!
前端·架构·github
文艺理科生9 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling9 小时前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
C澒9 小时前
Vue 项目渐进式迁移 React:组件库接入与跨框架协同技术方案
前端·vue.js·react.js·架构·系统架构