一. 如何优雅的声明类型
独立的类型或接口声明看起来似乎并没有那么难,到项目中糅合一下呢?
- 可能会有几十个类型声明;
- 类型声明可能出现在接口入参出参中、React 组件的 Props 和 State 中、函数方法中;
- 当项目到达一定规模,可以抽象出独立的库的时候,类型也需要抽象;
- ...
你可能遇到各种情况,会打破你对 TS 的掌控。如何是好?
独立声明
一个ts文件只声明一个类型或者接口,文件名为需要暴露的类型名称,方便检索和管理。
就近声明
当一个声明没有被外部引用或者依赖时,可以考虑就近放在使用的地方,典型的场景是React组件的Props和State的类型声明。
按职责分组
在项目中,需要声明类型的可大致分为两类:一类是model,也就是接口请求相关的,包括入参和出参;另一类是view,界面渲染相关的。因此,在独立声明的基础上,可以按照类型model和view的维度进行分组,相互独立。
那么问题来了,如果是独立的类型声明的话,怎么把model的数据应用到view呢?可能你需要一个 adapter 来做类型的的转换:DTOTypes -> adapter -> ViewTypes, 完成类似于将接口中的字符串映射成枚举类型这之类的转换。
杜绝“硬凑”关联
不要硬凑两个接口或者类型的关系,比如一个接口的创建和更新,可能字段都是一样,区别是一个有id另一个没有,于是我们可能就想着写一个类型然后 id 可选就好了。这样是少写了一个类型,但是可能会带来另外一些麻烦,比如带 id 的数据传给了新建的接口,但是 ts 检查不出来。所以,建议不要怕麻烦,直接拆分成 CreateInputDTO 和 UpdateInputDTO.
有限抽象
在杜绝“硬凑”关联的基础上,我们可以抽象出通用的声明。
万能药膏any
不是所有的类型声明都能一马平川的,当遇到确实解决不了的类型报错的时候,as any能带给你不一样的快感,但是不建议使用啊...
二、如何引用外部库
接下来聊聊第三方库在TS环境下的使用。
在 JS 中,npm 上有丰富的海量的库帮我们完成日常的编码,可能并不是所有的库都能完全被应用到 TS 中,因为有些缺少类型声明。
比如,在 TS 中使用 react , 你会得到这样的一个类型检查错误:
因为 react 的库中并没有类型声明。
现在比较通用的做法是,能力实现和类型实现独立成两个库,也就是你需要再安装类型声明的库: @types/react.
当遇到上述问题的时候,尝试安装一下 @types/[package].
然而,并不是所有的库都有类型声明的实现,也会有很多不支持 TS 的存在,然而又必须得使用这个库的时候该怎么办?
自己写声明!
以 progressbar.js为例,基本使用方法是:
import * as ProgressBar from 'progressbar.js';
new ProgressBar.Circle(this.$progress, {
strokeWidth: 8,
trailColor: '#e5e4e5',
trailWidth: 8,
easing: 'easeInOut'
});
如此我们便完成了一个简单的声明,当然实际使用中的 API 肯定比上述情况复杂,根据使用情况,用了哪些 API 或者参数,就补充那些的声明即可。
三. 如何组织一个 TS 项目
TS 项目的目录组织上,跟 JS 项目一样,补充好 types 的声明就可以了。
需要注意的是,将你希望对外暴露的能力相关的类型声明都暴露出去,不友好的声明会让接入你项目的人非常的痛苦,同时,在 package.json 中需要指定 type 的 path, 比如:"types": "dist/types/index.d.ts"
另外,务必加上 tslint, 更规范的去用 TS 实现功能,对于入门而言尤为重要。