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

如何根据参数值在TypeScript函数内部缩小返回类型?

问题描述

我尝试将一个接口的多个方法合并为一个带额外operation参数的函数,最终函数能正常调用,但函数内部无法正确缩小返回类型。之前的方案解决了参数类型缩小的问题,但返回类型的困扰依然存在:

interface Machine {
    doSomething: (arg: number) => string;
    doSomethingElse: (args: boolean) => number;
};

type MachineParameters = {
    [K in keyof Machine]: [K, ...Parameters<Machine[K]>];
}[keyof Machine];

const execute = <T extends MachineParameters>(...args: T): ReturnType<Machine[T[0]]> => {
    switch (args[0]) {
        case "doSomething":
            // 错误:Type '`${number}`' is not assignable to type 'MachineReturnTypes[T[0]]'.
            return `${args[1]}`;
        case "doSomethingElse":
            // 错误:Type 'number' is not assignable to type 'MachineReturnTypes[T[0]]'.
            return Number(args[1]);
        default:
            throw new Error("Unknown operation");
    }
};

// 正常:string类型
const x = execute("doSomething", 1);
// 正常:number类型
const y = execute("doSomethingElse", true);
解决方案

问题根源在于泛型T是MachineParameters的子集,TypeScript无法在switch分支中将T[0]与具体操作字符串关联,也就无法推断返回类型和T的对应关系。以下三种方法可以解决这个问题:

方法一:使用函数重载

通过显式定义重载签名,让TypeScript明确每个操作对应的参数和返回类型:

interface Machine {
    doSomething: (arg: number) => string;
    doSomethingElse: (args: boolean) => number;
};

// 定义重载签名,明确每个操作的参数和返回值
function execute(operation: "doSomething", arg: number): string;
function execute(operation: "doSomethingElse", arg: boolean): number;
// 实现签名,内部可以灵活处理
function execute(operation: keyof Machine, ...args: any[]): any {
    switch (operation) {
        case "doSomething":
            return `${args[0]}`;
        case "doSomethingElse":
            return Number(args[0]);
        default:
            throw new Error("Unknown operation");
    }
};

// 调用时类型推断正常
const x = execute("doSomething", 1); // string
const y = execute("doSomethingElse", true); // number

方法二:类型断言收窄返回类型

如果想保留泛型写法,可以在每个分支中用类型断言告诉TypeScript当前返回值的类型:

interface Machine {
    doSomething: (arg: number) => string;
    doSomethingElse: (args: boolean) => number;
};

type MachineParameters = {
    [K in keyof Machine]: [K, ...Parameters<Machine[K]>];
}[keyof Machine];

const execute = <T extends MachineParameters>(...args: T): ReturnType<Machine[T[0]]> => {
    switch (args[0]) {
        case "doSomething":
            return `${args[1]}` as ReturnType<Machine[T[0]]>;
        case "doSomethingElse":
            return Number(args[1]) as ReturnType<Machine[T[0]]>;
        default:
            throw new Error("Unknown operation");
    }
};

// 调用正常
const x = execute("doSomething", 1);
const y = execute("doSomethingElse", true);

方法三:重构为非泛型函数,利用联合类型自动收窄

将函数参数直接定义为MachineParameters联合类型,TypeScript会在每个switch分支中自动收窄参数和返回类型:

interface Machine {
    doSomething: (arg: number) => string;
    doSomethingElse: (args: boolean) => number;
};

type MachineParameters = {
    [K in keyof Machine]: [K, ...Parameters<Machine[K]>];
}[keyof Machine];

// 定义返回类型工具
type MachineReturn<K extends keyof Machine> = ReturnType<Machine[K]>;

const execute = (...args: MachineParameters): MachineReturn<typeof args[0]> => {
    switch (args[0]) {
        case "doSomething":
            // args自动收窄为["doSomething", number]
            return `${args[1]}`;
        case "doSomethingElse":
            // args自动收窄为["doSomethingElse", boolean]
            return Number(args[1]);
        default:
            throw new Error("Unknown operation");
    }
};

// 调用正常
const x = execute("doSomething", 1);
const y = execute("doSomethingElse", true);

内容的提问来源于stack exchange,提问作者Andreas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 08:23:17