本文的翻译于<<Effective TypeScript>>, 特别感谢!! ps: 本文会用简洁, 易懂的语言描述原书的所有要点. 如果能看懂这文章,将节省许多阅读时间. 如果看不懂,务必给我留言, 我回去修改.
技巧46:理解关于类型声明的三个版本
大多程序员都不喜欢花费过多时间在版本管理上。但是ts无法对版本管理提供什么帮助,反而会让版本管理更复杂一点。因为你有三个版本需要操心:
- 库的版本
- 库的对应类型声明版本(@types)
- ts的版本 当任意一个版本没有和其他的保持同步,就有可能导致报错。理解ts库管理复杂度,能让你规避上面这个问题。
当你安装一个库放到dependency依赖中,安装对应个@types到对应的devDependency:
$ npm install react
+ react@16.8.6
$ npm install --save-dev @types/react
+ @types/react@16.8.19
注意上面的主要版本和次要版本是匹配的(16.8)但是补丁版本却不一致(.6和.19)。@types的16.8表示的就是react的16.8版本。但是补丁版本(16.8.1, 16.8.2, ...)不会改变公共api,只是专注修复自身的bug。
版本管理可能在这些情况出错:
-
当你升级了库,但是忘记升级对应的@types。当你使用库的新功能的时候就会报错。或者通过类型检查但是可能在运行时报错。解决办法:升级@types好让版本保持统一。当你不想升级时,可能用类型扩充引入新函数,或者新方法。
-
你的@types版本比你的库的版本更新,这有可能是因为你先用一个库没有使用@types,当你安装@types时,安装了更新的版本。方法也类似,升级你的库,或者降低你的@types
-
你的@types要求更新版本的ts。如果不匹配也可能在@types声明时报错。解决办法就是升级ts,或者降级@types。如果你无法升级ts,那你可以用 declare module来删除类型。但是这种做饭很少见。
安装指定版本的@types:
npm install --save-dev @types/lodash@ts3.1 -
你可能遇到更复杂版本的@types的依赖。例如你一来 @types/foo和@types/bar。 与此同时@types/bar依赖不兼容的@types/foo:
node_modules/ @types/ foo/ index.d.ts @1.2.3 bar/ index.d.ts node_modules/ @types/ foo/ index.d.ts @2.3.4这种情况有时候在js运行阶段没问题,但是大多时候在类型检查时候会报错。当出现这种情况可以运行命令:
npm ls @types/foo来找到所有foo重复@types。解决办法是:升级@types/foo或者@types/bar来让版本兼容。
有些库,特别是ts写的库,喜欢绑定对应的类型声明。这通常由package.json的「types」字段表示,对应一个 .d.ts文件。
{
"name": "left-pad",
"version": "1.3.0",
"description": "String left pad",
"main": "index.js",
"types": "index.d.ts",
// ...
}
这种绑定好的类型能解决版本的不匹配。特别是用ts写的库,类型声明由tsc生成。但是这种版本绑定有自己的问题:
- 当绑定的类型声明出问题,无法通过类型扩充进行修复。
- 当ts升级后,可能出现类型声明的错误。@types可以随着库的实现而更新,但是绑定类型无法做到。这往往导致你只能维持比较旧的ts版本
- 当你想修复老版本库的类型的issue,@types具有同时维护同一库的不同版本的类型声明的机制,而绑定类型没有
- @types由升级有社区人员维护,而绑定类型没有。 我们应该尽量用@types,绑定类型可以使用,尽量使用tsc生成的。