Typescript返回类型取决于参数

Luk*_*kor 4 typing typescript

我正在尝试编写一个函数,该函数接受boolean类型的参数并根据输入的值返回两种类型之一。我发现了两种方法:

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

在这里,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";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

function calling(x: boolean) {
    dependsOnParameter(x);
}
Run Code Online (Sandbox Code Playgroud)

我懂了Argument of type 'boolean' is not assignable to parameter of type 'false'

有没有不用我就可以实现我想要的方法any

axe*_*l13 8

这是一种方法:

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

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

  • 为什么你必须强制类型 (11认同)
  • 相当大胆地断言一种特定的方式就是正确的方式。强制转换应该被视为“编译器本身无法弄清楚的事情”,我认为应该避免这种情况。 (3认同)

Tit*_*mir 5

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

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

此方法使用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
}
Run Code Online (Sandbox Code Playgroud)

最后一个签名是实现签名,并且不能公开访问。您可以通过复制使其可访问。编译器不够聪明,无法将两个重载与true/ 组合在一起false并确定返回类型为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";
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Lukor 添加了一个组合的更简单版本 (2认同)
  • 惊人的!尽管我发现值得注意的是,如果实现使用默认参数,而具有重复签名的方法却可以,那么较少签名的方法似乎不起作用。 (2认同)