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 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty8 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
Csvn8 小时前
diff 算法(虚拟 DOM Reconciliation)
前端
前端snow9 小时前
ai agent --- 文件存储
前端
Frag0ut9 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT_陈寒11 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技11 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
zeng不错11 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端
Latchh11 小时前
前端导出的JPEG红字发糊,质量要拉到100才清楚
前端·图像处理·人工智能·计算机视觉
默_笙12 小时前
🚦 请三个 AI 考官给 RAG 打分:量化评估实战(下)
前端·javascript