我试图将接口的方法组合成一个具有额外operation个参数的函数.结果的函数可以按预期被调用,但似乎无法在函数内缩小返回类型.

对于参数类型的缩小,earlier question of mine的答案很有帮助,但函数返回类型within的缩小对我来说仍然是一个谜:

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":
            // Error: Type '`${number}`' is not assignable to type 'MachineReturnTypes[T[0]]'.
            return `${args[1]}`;
        case "doSomethingElse":
            // Error: Type 'number' is not assignable to type 'MachineReturnTypes[T[0]]'.
            return Number(args[1]);
        default:
            throw new Error("Unknown operation");
    }
};

// Works: string
const x = execute("doSomething", 1);
// Works: number
const y = execute("doSomethingElse", true);

Playground

推荐答案

我喜欢用来缩小函数内部可能存在的多个重载的参数范围的技巧是将实现参数声明为重载的二元组的联合.这有点重复,但TS非常擅长按成员类型或大小缩小二元组.

// overloads
function execute(operation: 'doSomething', arg: number): string;
function execute(operation: 'doSomethingElse', arg: boolean): number;
// implementation
function execute(
    ...args: [operation: 'doSomething', arg: number] | [operation: 'doSomethingElse', arg: boolean]
): string | number {
    switch (args[0]) {
        case "doSomething":
            // args is narrowed to [operation: 'doSomething', arg: number]
            return `${args[1]}`;
        case "doSomethingElse": 
            // args is narrowed to [operation: 'doSomethingElse', arg: boolean]
            return Number(args[1]);
        default:
            // args is narrowed to never
            throw new Error(`Unknown operation ${args[0]}`);
    }
};

Playground

Typescript相关问答推荐

为什么当我试图从数据库预填充时,属性x不存在于类型{错误:字符串; }.ts(2339)上?

PrimeNG Inputnumber,具有自定义号码格式器

将对象属性路径描述为字符串数组的类型

即使子网是公共的,AWS CDK EventBridge ECS任务也无法分配公共IP地址

如何防止TypeScript允许重新分配NTFS?

动态调用类型化函数

打字脚本中泛型和直接类型重新映射的不同行为

使用泛型keyof索引类型以在if-condition内类型推断

学习Angular :无法读取未定义的属性(正在读取推送)

在分配给类型的只读变量中维护const的类型

如何在深度嵌套的Reaction路由对象中隐藏父级?

一个打字类型可以实现一个接口吗?

使用Redux Saga操作通道对操作进行排序不起作用

为什么我的动画状态在组件实例之间共享?

TypeScrip:使用Union ToInterval辅助对象,但保留子表达式

对于VUE3,错误XX不存在于从不存在的类型上意味着什么?

两个名称不同的相同打字界面-如何使其干燥/避免重复?

如何实现允许扩展泛型函数参数的类型

如何向我的自定义样式组件声明 custom.d.ts ?

将对象数组传递给 Typescript 中的导入函数