[英]Infer return type of function based on type guard
我有以下定义:
function foo(arg: number[] | number) {
if (Array.isArray(arg)) {
return [1]
}
return 0
}
我希望打字稿能够自动找出返回类型是什么。 由于类型保护isArray()
它知道 arg 是否是一个数组并且可以将返回类型显示为number[]
。 但是,使用foo(...)
其返回值显示为number[] | 0
number[] | 0
即使传递数组。
foo([]).push() // error because push doesnt exist on type 0
这是一个设计限制,一个错误,还没有实现,还是其他一些问题?
我不能明确指出这是设计限制,但我见过像jcalz和Titian Cernicova-Dragomir这样的专家引用类型推断受限的各种地方有时不是因为它不能做我们想要的,而是因为它这样做成本太高(就运行时成本或编译器中的代码复杂性而言)。 我怀疑这属于那个类别。
您可能知道这一点,但对于您的具体示例,您可以使用重载来获得所需的结果:
function foo(arg: number[]): number[];
function foo(arg: number): number;
function foo(arg: number[] | number) {
if (Array.isArray(arg)) {
return arg.map(v => v * 2);
}
return arg * 2;
}
foo([]).push(10);
我认为你正在寻找的是重载。
如下使用重载将解决您的问题:
function foo(arg1: number[]): number[];
function foo(arg1: number): 0;
function foo(arg1: any){
if(Array.isArray(arg1)){
return [0]
}
return 0
}
另一种选择是泛型:
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
- 所有其他数字都是 mehh... :)
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.