如何在TypeScript中实现基于参数的条件返回类型?
问题描述
我正在开发一个TypeScript服务,其中一个函数当前返回类型为User | null。我希望修改该函数,当throwIfNotFound参数设为true时,返回类型变为User——此时若未找到用户会抛出异常,从而在启用strictNullChecks的情况下避免冗余的空检查。
可复现示例:
interface IOptions { throwIfNotFound?: boolean; } interface User { id: number; } const userArray: User[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; function findUserById(id: number, options: IOptions): User | undefined { const { throwIfNotFound = false } = options; let user: User | undefined; if (id !== null) { user = userArray.find((u) => u.id === id); } if (throwIfNotFound && !user) { throw new Error("User not found"); } return user; } const user1 = findUserById(1, { throwIfNotFound: true }); // User存在不会抛出异常,user1实际不是undefined console.log(user1.id); // 'user1' is possibly 'undefined'.ts(18048)
请问能否通过TypeScript实现这一需求?
解决方案
完全可以实现,核心是利用TypeScript函数重载或者泛型条件类型,让类型系统根据参数的不同值推断对应的返回类型。
方法一:函数重载
这是最直观的实现方式,为不同的参数组合定义明确的返回类型:
interface IOptions { throwIfNotFound?: boolean; } interface User { id: number; } const userArray: User[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; // 重载签名1:当throwIfNotFound明确为true时,返回User类型 function findUserById(id: number, options: { throwIfNotFound: true }): User; // 重载签名2:其他情况(参数缺省或throwIfNotFound为false),返回User | undefined function findUserById(id: number, options?: IOptions): User | undefined; // 内部实现签名(仅用于逻辑编写,外部不可见) function findUserById(id: number, options: IOptions = {}): User | undefined { const { throwIfNotFound = false } = options; let user: User | undefined; if (id !== null) { user = userArray.find((u) => u.id === id); } if (throwIfNotFound && !user) { throw new Error("User not found"); } return user; } // 类型推断正确,无报错 const user1 = findUserById(1, { throwIfNotFound: true }); console.log(user1.id); const user2 = findUserById(4, { throwIfNotFound: true }); // 编译时类型为User,运行时抛出异常 const user3 = findUserById(4); // 类型为User | undefined
方法二:泛型条件类型
通过泛型参数捕获throwIfNotFound的具体布尔值,再用条件类型动态返回对应结果:
interface User { id: number; } const userArray: User[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; // 泛型T默认值为false,对应参数缺省的情况 function findUserById<T extends boolean = false>( id: number, options?: { throwIfNotFound?: T } ): T extends true ? User : User | undefined { const { throwIfNotFound = false } = options || {}; let user: User | undefined; if (id !== null) { user = userArray.find((u) => u.id === id); } if (throwIfNotFound && !user) { throw new Error("User not found"); } // 类型断言匹配条件类型的返回结果 return user as T extends true ? User : User | undefined; } // 类型推断正常 const user1 = findUserById(1, { throwIfNotFound: true }); console.log(user1.id); const user2 = findUserById(4); // 类型为User | undefined
两种方法对比
- 函数重载可读性更强,适合参数组合复杂的场景;
- 泛型条件类型写法更简洁,适合参数逻辑简单的场景,能自动适配参数的布尔字面量类型。
内容的提问来源于stack exchange,提问作者Kauan Polydoro
相关产品推荐
相关产品推荐

