
本文探讨了在typescript中如何根据函数参数返回不同类型的技术,避免使用庞大的联合类型。我们将首先分析常见的类型推断问题,然后介绍两种解决方案:一是利用索引访问类型结合类型断言,实现基本的类型安全;二是采用函数映射(function map)模式,通过从实现派生类型定义,构建出完全类型安全的条件返回函数,为复杂的条件逻辑提供更健壮、可维护的方案。
在TypeScript中,我们经常遇到需要编写一个函数,其返回类型根据传入参数的不同而动态变化的需求。例如,一个 fetch 函数可能根据 operation 参数(如 "get" 或 "post")返回不同结构的数据。直接使用一个包含所有可能返回类型的联合类型(如 GetResult | PostResult | ...)虽然可行,但在调用方侧,仍需要额外的类型守卫来区分具体类型,不够优雅。更理想的方式是,TypeScript能够根据传入的参数类型,自动推断出精确的返回类型。
考虑以下尝试实现基于参数条件返回的例子:
interface IdLabel {
id: number;
// ... 其他字段
}
interface NameLabel {
name: string;
// ... 其他字段
}
// 定义一个条件类型,根据T是number还是string返回不同的接口
type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel;
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
if (typeof idOrName === 'number') {
// 预期当idOrName是number时,返回IdLabel
return { id: idOrName }; // 报错:Type '{ id: number; }' is not assignable to type 'NameOrId<T>'.
} else {
// 预期当idOrName是string时,返回NameLabel
return { name: idOrName }; // 报错:Type '{ name: string; }' is not assignable to type 'NameOrId<T>'.
}
}尽管我们直观上认为 if (typeof idOrName === 'number') 内部的 return { id: idOrName } 应该与 NameOrId
为了解决上述问题,我们可以利用索引访问类型(Indexed Access Types)来定义返回类型,并在函数内部使用类型断言(Type Assertions)来辅助TypeScript理解。
首先,定义一个映射类型来关联操作名称和其对应的结果类型:
type GetResult = {
getData: string;
}
type PostResult = {
postData: string;
}
// 映射操作名称到其结果类型
type ResultType = {
get: GetResult;
post: PostResult;
// ... 更多操作
}
/**
* 根据操作名称返回不同类型结果的函数
* @param operation 操作名称,必须是ResultType的键
* @returns 对应操作的结果类型
*/
function fn<T extends keyof ResultType>(operation: T): ResultType[T] {
if (operation === "get") {
// 在此处进行类型断言,告诉TypeScript这个返回值是ResultType[T]
return { getData: "foo" } as ResultType[T];
} else if (operation === "post") {
// 同理,进行类型断言
return { postData: "bar" } as ResultType[T];
} else {
// 处理其他或未知操作,这里简化为抛出错误或返回默认值
throw new Error(`Unsupported operation: ${operation}`);
}
}
// 调用示例
const res1 = fn("get"); // res1 的类型被推断为 GetResult
console.log(res1.getData);
const res2 = fn("post"); // res2 的类型被推断为 PostResult
console.log(res2.postData);
// const res3 = fn("put"); // 编译错误:Argument of type '"put"' is not assignable to parameter of type '"get" | "post"'.解析:
优点:
缺点:
白瓜面试
白瓜面试 - AI面试助手,辅助笔试面试神器
162
查看详情
为了避免手动类型断言,我们可以采用一种更高级、更具类型安全性的模式:通过一个函数映射对象来定义所有操作,并从这个实现对象中派生出类型定义。这样,类型系统与运行时实现完美同步,无需任何断言。
type GetResult = {
getData: string;
}
type PostResult = {
postData: string;
}
// 1. 定义一个包含所有操作实现的对象
const _operations = {
get(): GetResult {
return { getData: "foo" };
},
post(): PostResult {
return { postData: "bar" };
},
// ... 更多操作
};
// 2. 从 _operations 对象中派生出 ResultType
// 遍历 _operations 的所有键,并获取对应函数的返回值类型
type ResultType = {
[key in keyof typeof _operations]: ReturnType<(typeof _operations)[key]>;
};
// 3. 定义一个类型安全的 operations 对象,它与 ResultType 关联
// 这一步是为了确保 _operations 的结构严格符合 ResultType
const operations: { [K in keyof ResultType]: () => ResultType[K] } = _operations;
/**
* 根据操作名称执行对应的函数并返回结果
* @param operation 操作名称,必须是 ResultType 的键
* @returns 对应操作的结果类型
*/
function fn<T extends keyof ResultType>(operation: T): ResultType[T] {
return operations[operation]();
}
// 调用示例
const resA = fn("get"); // resA 的类型被推断为 GetResult
console.log(resA.getData);
const resB = fn("post"); // resB 的类型被推断为 PostResult
console.log(resB.postData);
// const resC = fn("delete"); // 编译错误:Argument of type '"delete"' is not assignable to parameter of type '"get" | "post"'.解析:
优点:
缺点:
在TypeScript中实现基于参数的条件返回类型函数,避免使用大型联合类型,可以显著提升代码的可读性和类型安全性。
选择哪种方法取决于项目的具体需求和复杂性。对于大多数生产级应用,函数映射模式是更健壮、更可维护的选择,它将帮助您构建出更可靠、更易于理解的TypeScript代码。
以上就是TypeScript中实现基于参数的条件返回类型函数的详细内容,更多请关注其它相关文章!
# 如何用
# 南京银城建设 网站
# seo优化策划案
# seo代码优化怎么学
# 淮安推广营销策划公司有哪些
# 伊春刷长尾关键词排名
# 京东商智关键词排名查询
# 如皋市网站优化渠道
# 网站seo价格表
# 佛山微信营销推广代理
# 关键词排名模板怎么做好
# 体内
# 文件上传
# javascript
# 不同类型
# 一个函数
# 数据结构
# 适用于
# 返回值
# 报错
# 这是
# 编译错误
# 常见问题
# access
# typescript
# java
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
优化推广96088 】
【
技术知识133117 】
【
IDC资讯59369 】
【
网络运营7196 】
【
IT资讯61894 】
相关推荐:
《下一站江湖2》独孤剑诀习得方法
Excel如何快速合并单元格内容_Excel文本合并与函数操作技巧
《随手记》备份数据方法
Scipy Sparse CSR 矩阵非零元素行级遍历的最佳实践
j*a中ArrayBlockingQueue的使用
跨语言测试实践:使用Python Selenium测试现有J*a Web项目
《环球网校》设置报考省市方法
J*aScript模块加载器_RequireJS原理分析
J*aScript大数运算_BigInt使用指南
构建可配置的J*aScript加权点击计数器与共享总计功能
圆通快递官方入口不需要登录 在线查询入口快速查询
todesk如何添加信任设备_todesk信任设备设置教程
mail.qq.com登录入口 QQ邮箱网页版直达
如何使用 composer 和 aop-php 实现 AOP 编程?
店铺如何做视频号推广?做视频号推广有用吗?
微博网页版入口链接 微博网页版在线互动平台
CSS绝对定位与溢出控制:实现背景元素局部显示不触发滚动条
《杖剑传说》食谱大全
PPT页面尺寸怎么修改 PPT自定义幻灯片大小与方向设置【教程】
J*a实现任务清单管理_集合框架综合入门练手
Win11怎么设置分辨率 Win11显示设置调整分辨率及刷新率修改
批改网官网首页登录 批改网学生用户登录入口
Go语言中方法与接收器:指针和值类型的调用机制详解
解决 Vue 3 组件未定义错误:理解 createApp 与根组件的正确使用
realme 10 Pro息屏方案_realme 10 Pro省电策略
手机远程连接电脑方法
《万兴喵影》导出视频方法
Excel宏怎么删除_Excel中删除宏的详细操作流程
如何定制PrimeNG Sidebar的背景颜色
ToDesk远程摄像头功能使用方法_ToDesk远程视频画面查看设置教程
Win10锁屏时间怎么设置 Win10调整自动锁屏时间方法
Mac怎么关闭按键声音_Mac键盘打字音效设置
《360浏览器》设置摄像头权限方法
苹果手机怎么合并照片_苹果手机合并多张照片的操作方法
c++如何掌握指针的核心用法_c++指针入门到精通指南
Golang中的rune与byte类型区别是什么_Golang字符与字节处理详解
圆通快递包裹轨迹查询 圆通速递快件实时位置跟踪
Go语言反射机制下访问嵌入结构体中的被遮蔽方法
126邮箱申请入口官网_126邮箱注册免费登录2025
t3出行如何使用微信支付
win11怎么设置默认终端为Windows Terminal Win11替代CMD和PowerShell【技巧】
OPPO手机参数配置如何开启护眼模式_OPPO手机参数配置护眼模式开启指南
哈尔滨城市通昵称修改方法
PointNet++语义分割模型中类别变更引发的断言错误及标签处理策略
精通VS Code多光标编辑以实现闪电般快速的修改
Win10输入法不见了怎么办 Win10找回语言栏图标教程
J*aScript深度克隆:实现高效、健壮与安全的复杂对象复制
《搜书吧》阅读书籍方法
Highcharts雷达图径向轴数值标签实现教程
poki官网最新入口 poki小游戏大全入口
2025-11-27
运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。