带你体验一次类型编程实践
2023-02-18 16:41:21 时间
写作背景:
在看 uniapp 的教程时看到大量的 API 还是使用的 callback 的方式来接收 API 的执行结果,大量的 API 嵌套使用又会造成回调地狱的现象出现,在 API Promise 化 这一篇中提到了有部分API是已经做了 Promise 化,我这边用 cli 命令初始化的 vite+ts 的项目发现没办法使用对应的 Promise 化 API,所以还是通过一个工具类来实现一下,顺便试着再写一写 TypeScript 类型编程代码。
工具类编写准备:
下面这块代码我相信你有过类似想法的 jym 应该在网上看到过,通过定义这样一个高阶函数来将uniapp api 进行包装,并在执行这个高阶函数返回的函数时使用 Promise 来接管 api 成功失败所对应的回调函数。
export const promisify = (api) => {
return (options, ...params) => {
return new Promise((resolve, reject) => {
api(Object.assign({}, options, {
success: resolve,
fail: reject
}), ...params);
});
}
}
注:高阶函数说的简单点就是传入一个函数并返回一个函数,切记返回的是函数还没有执行,遇到了多少写防抖节流的小伙伴是忘了执行还各个群里问 why 的~
发挥TypeScript类型的强大之处:
Typescript内置类型工具:
- Parameters:提取函数类型的参数所组成的类型列表;
- NonNullable:提取传入类型除 null、undefined 以外的类型;
类型编程分析:
- promisify 函数的输入类型约束:输入的内容均是uniapp api(函数),所以使用泛型来约束输入的类型;
const promisify = <P extends (...args: any) => any>(api: P) => {}
- promisify 返回的函数的输入类型约束:这个输入类型实际是 uniapp api 执行的的形参类型,所以需要使用内置的类型工具(1)来提取,我们只提取类型列表的第一项即可,有实际需要可以再扩展:
type ParameterFirst<T extends (...args: any) => any> = Parameters<T>[0];
export const promisify = <P extends (...args: any) => any>(api: P) => {
return (options: ParameterFirst<P>) => {}
}
- 执行完 promisify 返回的函数后 Promise 对象的类型约束:这里只能通过泛型约束成功状态的类型,成功状态的类型实际上是 uniapp api 选项中 success 属性(回调函数)返回的类型。我们需要先提取到 success 属性,然后再次使用内置类型工具(1)来提取回调函数的返回类型。
type ParameterSuccess<T extends (...args: any) => any> = ParameterFirst<NonNullable<Parameters<T>[0]['success']>>;
注:因为Parameters存在可能得到一个 undefined 类型的情况,所以使用 NonNullable 来进行包装。
完整的promisify工具类:
/**
* uni.request({
* url: 'https://jsonplaceholder.typicode.com/todos/1',
* success: (res) => {
* console.log(res.data);
* }
* });
*
* promisify(uni.request)({ url: '' }).then(res => {
* // res.data
* }).catch(err => {
*
* });
*
* @param api
* @returns
*/
/**
* 提取传入函数的第一个形参参数的类型
*/
type ParameterFirst<T extends (...args: any) => any> = Parameters<T>[0];
/**
* 提取传入函数的第一个形参参数中key为success的参数的类型;
* 因success类型为函数类型,所以再次提取success函数的第一个形参参数的类型
*/
type ParameterSuccess<T extends (...args: any) => any> = ParameterFirst<NonNullable<Parameters<T>[0]['success']>>;
export const promisify = <P extends (...args: any) => any>(api: P) => {
return (options: ParameterFirst<P>) => {
return new Promise<ParameterSuccess<P>>((resolve, reject) => {
api(
Object.assign({}, options, {
success: resolve,
fail: reject,
}),
);
});
};
};
结语:
既然选择 TypeScript 来编写项目,就要尽可能的发挥出 TypeScript 作用,在万般无奈的时候再用 any 也不迟 ~~~
相关文章
- 数据结构(java版)学习笔记(四)——线性表之循环链表
- 数据结构(java版)学习笔记(三)——线性表之单链表
- 数据结构(java版)学习笔记(二)——线性表之顺序表
- 数据结构(java版)学习笔记(一)——线性表
- 数据结构(java版)学习笔记(序章)
- 抓 https 加密数据,偷偷摸摸爽得很!
- 小游戏赛道迎来新一轮增长机会,技术升级实现多平台布局
- Photoshop 2021正式版更新,附全系列下载
- Ps | Adobe Photoshop 2023 for Win 24.1 中文激活版下载及安装教程
- 简单易用的监控告警系统 | HertzBeat 在 Rainbond 上的使用分享
- 原来Docker容器中设置时区这么简单
- 小游戏进入增长快车道,行业变现模式分析
- (一)汇编语言——基础知识
- ghost系统后只有C盘了别的盘的文件怎样恢复
- (二)汇编语言——寄存器
- (三)汇编语言——DOSBox
- 分布式是大数据处理的万能药?
- SAP ABAP 报表屏幕输入字段如何实现联动效果试读版
- 如何给 SAP ABAP ALV 报表的修改功能添加自定义校验逻辑试读版
- 参加 Spartacus 开源项目开发时需要注意的一些编程规范