TS 泛型的小试牛刀,踩坑踩坑

2022-05-11 · 周三一般雷雨

前段时间我应该提到过,我在公司项目上参考 AHooks 写了个 useRequest Hooks,今天打算继续完善下它的 TS 类型定义,想让它支持自动识别传入的参数,并原封不动的提供到其他方法(onSucceed / onFailed 等)上。

想到这个参数可能为空,我还错误的用了重载去写,实际上并不需要。最后用到了 Rest 参数这个特性(才了解到,真的菜),一般来说这东西的类型是 string[]

花了晚上将近 2 小时的时间研究,陆陆续续解决好了应用代码里面的报错,终于缩小了 Debug 范围,发现是 Hooks 返回对象里面的类型不对,最后改成了这样。这样写确实是正确的,但我还发现了更奇怪的问题,可选参数竟然变成了必须项?为了方便说明,下面这几段代码都是简化后的例子:

interface Result<T extends any[]> {
  send: (...args: T) => void
}
function Request<T extends any[]>(api: (...args: T) => void, onSucceed?: (data: string, ...params: T) => void): Result<T> {
  return {
    send: (...args) => {
      onSucceed && onSucceed("test", ...args);
    }
  }
}

// 注意看 (str, id) 这个位置
const a = Request((id?: number) => `id: ${id}`, (str, id) => console.log("args", str, id));

// ⚠️ 异常:应有 1 个参数,但获得 0 个,未提供 rest 形参“args”的实参
a.send();
// ✅ 正常
a.send(14);

结合上面的 Result,根据这个类型定义,api 函数传入多少个参数,send 方法也就会传回来多少个参数。奇怪的地方就是,如果有一个参数设置成了可选,send 方法会提示不能为空。我就纳闷了,为什么它被自动转换成了必须项呢?

起初我尝试用 void 代替可选项(id? 变成了 id: number | void),这确实可以,但又可能导致onSucceed 里面需要额外判断 id 是否不存在。假如它可能是对象,就无法使用 params ?. type 这种链式判断符了。

最后发现,这其实是因为除了 api 函数,onSucceed 函数里面没有将参数 id 设置成可选项,才使得 id“莫名其妙”变成了必填,最终send 方法报错。在试错期间,我还意外发现了下面这段代码的写法不会报错,为什么呢?

function RequestB<T extends any[]>(api: (...args: T) => void, onSucceed?: (...args: T) => void): Result<T> {
  return {
    send: (...args) => {
      onSucceed && onSucceed(...args);
    }
  }
}

// 这里的 id? 没有指定类型
const b = RequestB((id?) => "id", (id) => console.log(id));

b.send();
b.send(123);

相对于第一个例子,这里的 id? 并没有指定类型,默认是 any,而 any 本身是不会参与 TS 校验的,所以给了我“它能工作”的假象,一旦加上类型,就死翘翘。

虽然说这一个鬼东西看了这么久,也绕了不少弯子,显得我有些愚蠢(@Innei:这还不是体操,就是一个简单的泛型),可这么认真的去琢磨之后,的确就更了解具体的原因了,感觉 TS 我还是得从头到尾,重新认识一下才行了==

あまい匂いをさがして

あまい匂いをさがして

Foxtail-Grass Studio
Paul

Paul

特立独行的一只前端菜狗。这篇日记编写大概耗时了 0 分钟,内容均为个人原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!如本站内容对你有所帮助的话,不妨 捐助支持 一下?

近期评论

鲍小螺: 前辈多多指教!ahu: 后生可畏寻梦xunm: 真不错,板子很好看。timochan: 太惨了( ,更新暴毙,如果恢复没成功,数据也 dump 不出来鲍小螺: 在这部分对话中,广树和保罗继续讨论生活的不同方面。保罗提到了技术更新和国内的优秀 IT 技术。广树解释了在国内积累的经验如何在日本产生穿越的感觉,并表达了对于日本生活节奏的喜爱。他还提到了医疗水平的差异和对于生活方式的感受。保罗表示,通过动漫和现实的对比,艺术来源于现实,日本生活的确有着独特之处。他们讨论了国内的生活节奏和就医等方面的压力,以及个人选择的自由。最后,他们也谈到了不结婚不买房的选择和对于房价的困扰。鲍小螺: 该对话进一步讨论了房地产和税收的问题。保罗提到了国内的房地产税和增值税以及日本的固定资产税。广树解释了日本房地产税的收取方式,以及房产税对于国内房产的影响。他认为,与国内相比,日本的房子质量和服务更好。保罗提出疑问,为什么自己拥有的地也要交税。广树解释了类似增值税的原理,并指出在日本拥有房产是稳定安全的。最后,保罗表示从广树的角度来看,情况确实是如此。鲍小螺: 这篇文章的聊天记录也尝试过用 GPT 总结,结果并不是太好,不知道是不是 Prompt 的问题,实际出来的内容过于简练了,于是又耗费了半小时写完,呼~
奇趣音乐盒技术源于 Kico Player
Emmm,这里是歌词君