Typescript return 类型取决于参数

Typescript return type depending on parameter

我正在尝试编写一个函数,该函数采用布尔类型和 returns 两种类型之一的参数,具体取决于输入值。我找到了两种方法:

function dependsOnParameter<B extends boolean>(x: B): B extends true ? number : string {
    if (x) {
        return 3;
    } else {
        return "string";
    }
}

在这里,TypeScript 表示 Type '3'/'"string"' is not assignable to type 'B extends true ? number : string'.

我的其他方法是这样的:

function dependsOnParameter(x: true): number;
function dependsOnParameter(x: false): string;
function dependsOnParameter(x: boolean): number | string {
    if (x) {
        return 3;
    } else {
        return "string";
    }
}

这个编译;但是,如果我尝试使用我的函数:

function calling(x: boolean) {
    dependsOnParameter(x);
}

我得到 Argument of type 'boolean' is not assignable to parameter of type 'false'

有什么方法可以不使用 any 来达到我想要的效果吗?

两种方法都有效。如果您的函数在 return 中使用条件类型,则需要使用类型断言,因为 typescript 不会尝试推断条件类型,因为它包含一个自由类型参数:

function dependsOnParameter<B extends boolean>(x: B): B extends true ? number : string {
    if (x) {
        return 3 as any;
    } else {
        return "string"as any;
    }
}

此方法使用了您想避免的 any

第二种方法我们可以在不诉诸类型断言的情况下开始工作,只需复制最后一个签名:

function dependsOnParameter(x: true): number;
function dependsOnParameter(x: false): string;
function dependsOnParameter(x: boolean): number | string
function dependsOnParameter(x: boolean): number | string {
    if (x) {
        return 3;
    } else {
        return "string";
    }
}

function calling(x: boolean) {
    dependsOnParameter(x); // returns number| string
    dependsOnParameter(true); // returns number
    dependsOnParameter(false); // returns string
}

最后一个签名是实现签名,不可公开访问。您可以通过复制它来使其可访问。编译器不够聪明,无法将两个重载与 true/false 组合起来,并决定 return 类型为 string|number

编辑

我们还可以结合这两种方法来减少签名:

function dependsOnParameter<B extends boolean>(x: B): B extends true ? number : string 
function dependsOnParameter(x: boolean): number | string{
    if (x) {
        return 3;
    } else {
        return "string";
    }
}

可以这样写

function dependsOnParameter<B extends boolean, C = B extends true ? number : string>(x: B): C {
    if (x) {
        return 3 as unknown as C;
    } else {
        return "string" as unknown as C;
    }
}

这是正确的方法:

function dependsOnParameter<B extends boolean>(x: B): B extends true ? number : string {
    return (x === true ? 3 : "string") as B extends true ? number : string;
}

这里,条件本身(B extends true ? number : string)被认为是一种类型。这种类型称为 Conditional Type.