本篇是「一起学习TypeScript」 系列的第3篇,接下来笔者将持续深耕,不定时更新一系列精彩纷呈的TypeScript文章,旨在解答使用TypeScript过程中的各种疑难杂症,一起探索TS的无穷魅力!
【TS系列回顾】:
TS系列(1): React中能否使子组件实现“类型安全”?
一、any之“毒”
any
是TypeScript中一个极其强大的类型,它可以让你像使用JS一样地对待一个值(而不是TS)。这就意味着它禁用了TS的所有特性–类型检查、自动完成和安全性等。
一个例子🌰:
const myFunction = (input: any) => {
input.someMethod();
};
// This will fail at runtime!
myFunction("abc");
频繁使用any
通常被认为是有害的,甚至有ESlint Rules用来阻止any
的使用,从而让开发人员完全放弃使用any
然而,在一些特定的场景中,any
其实是正确的选择。接下来,本文将介绍可以合法使用any
的一些场景。
二、可合法使用any的场景
1、类型参数约束
假设我们想要在TS中实现ReturnType
程序,它采用函数类型(function type)并返回其返回值的类型。
我们需要创建一个将function type作为类型参数的 泛型类型(generic type)。如果这时我们不能使用any
,也许我们会使用unknown
,如下所示:
type ReturnType<T extends (...args: unknown[])=> unknown >=
T extends (...args: unknown[]) => infer R ? R: never;
主要看下代码中的这句**T extends (...args: unknown[]) => unknown
** , 它意味着只允许接收参数为unknown[]
的数组,并且返回unknown
。
这么写,对于没有参数的函数来说,上面的ReturnType
写法似乎是可行的:
但是,当我们向myFunction
中增加1个参数,问题出现了:
事实上,只有当我们把参数设置为input: unknown
时,上面定义的ReturnType
才会生效:
因此我们创建了一个ReturnType
,该函数仅仅适用于接收unknown
作为参数的函数。😅😅。这显然不是我们想要的效果,我们的初衷是希望ReturnType
对任何函数都起作用!
解决方案:使用**any[]
** 改写上面的ReturnType
type ReturnType<T extends (...args: any [] ) => any> =
T extends (...args: any [] ) => infer R ? R : never;
这时,我们再来使用ReturnType
,发现它是可以按照我们的期待正常工作的:
此种场景下可以安全使用any
的原因是:我们故意定义了一个宽类型(wide type),也就是“我不在乎接收什么函数,只要它是一个函数,就可以使用ReturnType
”。这时,使用any
就是安全的。
2、从泛型函数返回条件类型
在一些场景下,TS的窄化能力(narrowing ability,指通过条件语句、类型守卫等逐步缩小或确定变量的具体类型)并不想我们想的那么好。
假设,我们想要创建一个函数,该函数可以根据不同的条件返回不同的类型:
可以看出youSayGoodbyeISayHello
函数并没有按照我们期待的那样运行:当我们传"hello"
的时候,期待返回的是"goodbye"
,但是实际返回的结果却是 "hello"|"goodbye"
😒
此时,我们可以使用条件类型来解决这个问题:
但是,其实👆🏻这么写也会飘红,实际上:
🤯看起来TS似乎没有将条件类型与运行时逻辑相匹配,这个函数不能返回 "hello"
或者 "goodbye"
🤯
当然,我们是可以使用**as
**强制使其成为正确的条件类型:
为了让代码看起来更简洁,我们可以抽取通用的逻辑到一个泛型类型中:
然而,实际上👆🏻这种场景中,使用any
更合理。
你也许会说,这里使用any
会使得我们的函数类型安全性降低。但这种情况下,通常最好是使用**as any
的同时再为函数的行为添加单元测试**,两者结合基本可以保证类型安全(且代码没有那么繁琐)。
三、结论
问题仍然存在:你是否应该在你的代码库中禁止使用any
?
我认为,总的来说,答案是yes。你应该打开ESLint规则来阻止any
的使用,并且应该尽可能地避免它。
但是,凡事皆不可一棒子打死,确实存在一些场景使用any
更合适。这时,你可以使用eslint-disable
去绕过any
使用限制 😉
如果你发现了其他可以合法使用或使用**any
**更合适的场景,可以在评论区评论哦!
原文链接:https://juejin.cn/post/7353447472557211711 作者:爆浆小丸子