我有以下定义:
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
这是设计限制,错误,尚未实现还是其他问题?
答案 0 :(得分:5)
我不能明确指出这是设计限制,但是我看到jcalz和Titian Cernicova-Dragomir之类的专家列举了多个地方进行类型推断的地方,有时并不是因为它不能做我们想要的,但是因为这样做会太昂贵(就运行时成本或编译器中的代码复杂性而言)。我怀疑这符合该类别。
您可能知道这一点,但是对于您的特定示例,可以使用重载来获得所需的结果:
this.$options.computed
答案 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的值不是sound。 T
的形状是由调用者指定的,因此我们不知道它的确切含义。
想象一下,数字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