使用 TypeScript 也快一年了,本文主要分享一些工作常用的知识点技巧和注意点。
本文适合了解 TypeScript 或有实际使用过一段时间的小伙伴。
如果对 TypeScript 基础知识不熟悉的可以看下我这篇文章:TypeScript 入门知识点总结
操作符
类型别名
用来给一个类型起个新名字
1 | type Props = TextProps |
keyof
用于获取某种类型的所有键,其返回类型是联合类型。
1 | interface Person { |
联合类型
和逻辑 “||” 一样都是表示其类型为多个类型中的任意一个
比如当你在写Button 组件的时候:
1 | export type ButtonSize = 'lg' | 'md' | 'sm' |
交叉类型
将多个类型合并成一个类型
比如当你给一个新的 React 组件定义 Props 类型,需要用到其它若干属性集合
1 | type Props = TypographyProps & ColorProps & SpaceProps |
extends
主要作用是添加泛型约束
1 | interface WithLength { |
typeof
typeof 是获取一个对象/实例的类型
1 | interface Person { |
泛型工具类型
Partial
将某个类型里的属性全部变为可选项。
1 | // 实现:全部变可选 |
例子
1 | interface Animal { |
Readonly
它接收一个泛型 T,用来把它的所有属性标记为只读类型
1 | // 实现:全部变只读 |
1 | interface Person { |
Required
将某个类型里的属性全部变为必选项。
1 | // 实现:全部变必选 |
1 | interface Person { |
Record
1 | // 实现:K 中所有属性值转化为 T 类型 |
Record 生成的类型具有类型 K 中存在的属性,值为类型 T
1 | interface DatabaseInfo { |
Pick
1 | // 实现:通过从Type中选择属性Keys的集合来构造类型 |
用于提取接口的某几个属性
1 | interface Animal { |
Exclude
1 | // 实现:如果 T 中的类型在 U 不存在,则返回,否则不返回 |
将某个类型中属于另一个的类型移除掉
1 | interface Programmer { |
Omit
1 | // 实现:去除类型 T 中包含 K 的键值对。 |
作用与 Pick 相反,还是直接看代码容易理解
1 | interface Animal { |
ReturnType
1 | // 实现:获取 T 类型(函数)对应的返回值类型 |
获取函数返回值类型
1 | function bar(x: string | number): string | number { |
运算符
可选链运算符
可选链操作符(?.
)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。如果遇到 null 或 undefined 就可以立即停止某些表达式的运行
这个在项目中比较常用,也很好用。
比如我们数据都是从 api 返回的,假设有这么一组数据
1 | // 请求 api 后才返回的数据 |
前端接收后拿来取值,apiRequestResult.data.address.city
,正常情况取得到值,如果后台 GG 没有返回 address 这个对象,那么就会报错:
1 | TypeError: Cannot read property 'city' of undefined |
这个时候需要前端处理了,比如最直接的就是
1 | apiRequestResult && apiRequestResult.data && data.address && data.address.city |
或者 lodash 库方法也能解决
1 | import * as _ from 'lodash' |
项目中如果都是这么处理,未免太过于繁琐,特别对象很多的情况下,这时就可以使用 TS 的可选链操作符,
1 | apiRequestResult?.data?.address?.city |
上述的代码会自动检查对象是否为 null 或 undefined,如果是的话就立即返回 undefined,这样就可以立即停止某些表达式的运行,从而不会报错。
当你在 React 中使用 ref 封装判断元素是否包含 XX 元素时,也会用到这个操作符
1 | const isClickAway = !childRef.current?.contains?.(e.target) |
空值合并运算符
空值合并操作符(??
)是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。
与 ||
操作符类似,但是 ||
是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。如0, '', NaN, null, undefined
都不会被返回。
1 | const foo1 = null |
实际开发也可以混用?.
和??
1 | const title = document.getElementById("title")?.textContent ?? ""; |
非空断言运算符
在上下文中当类型检查器无法断定类型时,这个运算符(!
)可以用在变量名或者函数名之后,用于断言操作对象是非 null 和非 undefined 类型。不过一般是不推荐使用的
这个适用于我们已经很确定知道不会返回空值
1 | function print(name: string | undefined) { |
要解决这个报错,可以加入判断
1 | function print(name: string | undefined) { |
但这样写代码就显得冗长一点,这时你非常确定不空,那就用非空断言运算符
1 | function print(name: string | undefined) { |
从而可以减少冗余的代码判断
项目中的细节应用
尽量避免 any
避免 any,但检查过不了怎么搞?可以用 unknown(不可预先定义的类型)代替
给个不是很好的例子,因为下面例子是本身不对还强行修正错误。大概情况是有些未知数据的情况,需要强定义类型才能过,可以用(xx as unknown) as SomeType
的形式,当然这里只是例子,项目中类型检查逼不得已的情况下可能会使用
1 | const metaData = { |
可索引的类型
一般用来约束对象和数组
1 | interface StringObject { |
1 | interface StringArr { |
注释
通过 /** */
形式的注释让 TS 类型做标记提示,编辑器会有更好的提示
1 | /** Animal common props */ |
ts-ignore
还是那样,尽可能用 unknown 来代替使用 any
如果你们项目禁用 any,那么 ts-ignore 是一个比 any 更有潜在影响代码质量的因素了。
禁用了但有些地方确实需要使用忽略的话,最好注释补多句理由。
比如有些函数单元测试文件,测试用例故意传入不正确的数据类型等,有时是逼不得已的报错。
1 | // @ts-ignore intentionally for test |
- 个人技术博文 Github 仓库
觉得不错的话欢迎 star,给我一点鼓励继续写作吧~