You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 12:32:46