forked from ascoders/weekly
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
62 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
如何为 TS 类型写单测呢? | ||
|
||
最简单的办法就是试探性访问属性,如果该属性访问不到自然会在异常时出现错误,如: | ||
|
||
```ts | ||
import { myLib } from "code"; | ||
myLib.update; // 正确 | ||
``` | ||
|
||
如上所示,如果 `myLib` 没有正确的开放 `update` 属性将会提示错误。但这种单测并不是我们要讲的类型。想一想,如果我们只开放 `.update` API 给用户,但框架内部可以使用全量的 `.update`、`.add`、`.remove` 方法,如何验证框架没有把不必要的属性也开放给了用户呢? | ||
|
||
一种做法是直接访问类型提示,此时会出现错误下划线: | ||
|
||
```ts | ||
myLib.add | ||
~~~ // Property 'add' does not exist on type MyLib | ||
``` | ||
|
||
此时说明代码逻辑正常,但却抛出了 ts 错误,这可能会阻塞 CI 流程,而且我们也无从判断这个报错是否 “实际山是逻辑正确的表现”,所以 “不能出现某个属性” 就不能以直接访问属性的方式实现了,我们要做一些曲线方案。 | ||
|
||
## 利用特殊类型方法 | ||
|
||
我们可以利用 `extends` 构造三元类型表达式,逻辑是如果 `myLib` 拥有 `.add` 属性就返回 a 类型,否则返回 b 类型。因为 `myLib` 不该提供 `.add` 属性,所以下一步判断该新类型一定符合 b 即可: | ||
|
||
```ts | ||
const check: typeof myLib extends { add: any } ? number : number[] = []; | ||
check.length; // 该行在没有 .add 属性时不会报错,反之则报错 | ||
``` | ||
|
||
因为我们给的默认值是字符串,而预期正确的结果也是进入 `number[]` 类型分支,所以 `check.length` 正常,如果某次改动误将 `.add` 提供了出来,`check.length` 就会报错,因为我们给值 `[]` 定义了 `number` 类型,访问 `.length` 属性肯定会出错。 | ||
|
||
## 利用赋值语句判断 | ||
|
||
另一种简化的办法是利用 `true` or `false` 判断变量类型是否匹配,如: | ||
|
||
```ts | ||
const check: typeof fn extends (a: any) => any ? true : false = true; | ||
``` | ||
|
||
如果 `fn` 满足 `(a: any) => any` 类型,则 `check` 的类型限定为 `true`,否则为 `false`,所以当 `fn` 满足条件时该表达式正确,当 `fn` 不满足条件式,我们将变量 `true` 赋值给类型 `false` 的对象,会出现报错。 | ||
|
||
## 可以将 ts 转换为 js 吗? | ||
|
||
也许你会有疑问,可以将 ts 类型校验错误转换为 js 对象吗?这样就可以用 `expect` 等断言结合到测试框架流程中了。很可惜,至少现在是不行的,只能做到利用 js 变量推导类型,不能利用类型生成变量。 | ||
|
||
## 总结 | ||
|
||
总结一下,如果想判断某些类型定义未暴露给用户,而实际上在 js 变量里是拥有这些属性的,就只能用类型方案判断正确性了。 | ||
|
||
比如变量 `myLib` 实际上拥有 `.update` 与 `.add` 方法,但提供给用户的类型定义刻意将 `.add` 隐藏了,此时校验方式是,利用一个跳板变量 `check`,使用 `extends` 判断其是否包含 `add` 属性,再利用特殊类型方法或者直接用赋值语句判断 `extends` 是否成立。 | ||
|
||
> 讨论地址是:[精读《如何为 TS 类型写单测》· Issue #446 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/446) | ||
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。** | ||
|
||
> 关注 **前端精读微信公众号** | ||
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg"> | ||
|
||
> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)) |