根据类型防护推断函数的返回类型

时间:2020-09-27 11:07:22

标签: typescript

我有以下定义:

function foo(arg: number[] | number) {
    if (Array.isArray(arg)) {
        return [1]
    }

    return 0
}

我希望打字稿能自动找出返回类型是什么。由于类型为isArray(),它知道arg是否为数组,并且可以将返回类型显示为number[]。但是,即使传递数组,使用foo(...)也会将其返回值显示为number[] | 0

  foo([]).push() // error because push doesnt exist on type 0

这是设计限制,错误,尚未实现还是其他问题?

3 个答案:

答案 0 :(得分:5)

我不能明确指出这是设计限制,但是我看到jcalzTitian Cernicova-Dragomir之类的专家列举了多个地方进行类型推断的地方,有时并不是因为它不能做我们想要的,但是因为这样做会太昂贵(就运行时成本或编译器中的代码复杂性而言)。我怀疑这符合该类别。

您可能知道这一点,但是对于您的特定示例,可以使用重载来获得所需的结果:

this.$options.computed

Playground link

答案 1 :(得分:0)

我认为您正在寻找的是overloads

按如下所示使用重载将解决您的问题:


function foo(arg1: number[]): number[];
function foo(arg1: number): 0;
function foo(arg1: any){
    if(Array.isArray(arg1)){
        return [0]
    }

    return 0
}

答案 2 :(得分:0)

另一种选择是Generics

function foo<T extends number[] | number>(arg:T):T {
    if (Array.isArray(arg)) { return [1] as T }
    return 0 as T
}

foo([] as number[]).push(10) // works
foo(42).push(10) // error as expected

foo的使用者得到完美的类型。在内部,我们使用类型断言,因为return ed的值不是soundT的形状是由调用者指定的,因此我们不知道它的确切含义。

想象一下,数字42的恋物癖俱乐部拥有foo-其他所有数字都是…………)

然后像
function foo<T extends number[] | number>(arg:T):T {
    if (Array.isArray(arg)) { return [1]}
    return 1
}
foo(42); // T instantiated as 42

显然是不能容忍的。

虽然这个例子是人为设计的-俱乐部听起来很整洁-但您可能会明白,为什么第一个例子需要为type asserted

一个更逼真的声音示例:
function ensureDefined<T extends number[] | number>(initializer: () => T, arg?: T): T {
    if (arg === undefined || Array.isArray(arg) && arg.length === 0) {
        return initializer()
    } else return arg
}

ensureDefined(() => [42], [] as number[]).push(10) // works
ensureDefined(()=> 42, undefined) // error as expected

Here is a Playground