如何让TypeScript自动推断泛型Result包裹的函数返回类型?
让TypeScript自动推断Result泛型的区分联合类型,无需手动定义T类型
问题分析
你定义了泛型Result类型用于封装操作结果,但类方法中直接返回对象字面量时,TypeScript会将返回类型推断为非区分联合类型({ ok: boolean; value?: T; error?: E }),而非预期的Result<T, E>区分联合。这会导致类型守卫失效——比如判断!result.ok后,TS仍提示result.error可能为undefined。手动指定返回类型又需要维护额外的MyDataType,无法自动同步数据库查询的类型变化。
解决方案:使用辅助函数约束返回类型
通过创建两个简单的辅助函数ok和err,明确返回Result类型的字面量联合,让TypeScript自动推断泛型参数T和E,同时保证返回类型是区分联合类型,类型守卫可以正常工作。
完整代码示例
export type Result<T, E = Error> = | { ok: true; value: T } | { ok: false; error: E }; // 辅助函数:封装成功结果,自动推断T类型 const ok = <T>(value: T): Result<T> => ({ ok: true, value }); // 辅助函数:封装错误结果,自动推断E类型(默认Error) const err = <E = Error>(error: E): Result<never, E> => ({ ok: false, error }); class DataRepository { async getSomeData() { const data = await Promise.resolve( Math.random() < 0.5 ? null : { something: 42 } ); if (!data) { return err(new Error("Invalid ...")); } return ok(data); } } async function example() { const repo = new DataRepository(); const result = await repo.getSomeData(); if (!result.ok) throw result.error; // 类型守卫正常工作,无undefined提示 const something = result.value.something; // 正确识别value的类型,无undefined提示 }
原理说明
- 辅助函数
ok和err明确返回Result<T>和Result<never, E>类型,其中ok属性是字面量类型true/false,而非宽泛的boolean。 - TypeScript会自动从传入的
value和error参数推断出泛型T和E的具体类型,无需手动定义。 - 最终方法的返回类型会被推断为
Promise<Result<{ something: number }, Error>>,属于标准的区分联合类型,类型守卫可以正确缩小类型范围。
替代方案:显式注解返回类型(无需手动定义T)
如果不想使用辅助函数,也可以直接给方法添加返回类型注解,利用TypeScript的类型推断自动填充泛型参数:
class DataRepository { async getSomeData(): Promise<Result<Awaited<ReturnType<typeof this.prisma.dataset.findMany>>>> { const data = await this.prisma.dataset.findMany({ ... }); if (!data) { return { ok: false, error: new Error("Invalid ...") }; } return { ok: true, value: data }; } }
这种方式通过ReturnType<typeof ...>获取数据库查询方法的返回类型,再用Awaited处理异步类型,无需手动定义MyDataType,但写法比辅助函数繁琐。
内容的提问来源于stack exchange,提问作者Haardik
相关产品推荐
相关产品推荐

