我有两个使用以下方法的名义上的类型的函数(抛开我为什么要这样做的方式-简化此示例以试图阐明我的问题):
interface OneArgFunc<T> {
label: "oneArgFunc"
innerFunc:(x: string, y:T)=>void
}
interface TwoArgFunc<T> {
label: "twoArgFunc"
innerFunc: (a:number, b:string, c:T)=>void
}
我也将两者结合在一起,并使用了类型保护器来区分:
type UnionFunc<V> = OneArgFunc<V> | TwoArgFunc<V>
// Type guard functions
function isOneArgFunc<V>(func: UnionFunc<V>): func is OneArgFunc<V> {
return func.label === "oneArgFunc"
}
function isTwoArgFunc<V>(func: UnionFunc<V>): func is TwoArgFunc<V> {
return func.label === "twoArgFunc"
}
但是,如果我在联合中调用类型守卫之一,则不会将其余部分(“ else”语句)缩小到联合的另一半:
function transfomer<U extends UnionFunc<any>>(func:U){
if(isOneArgFunc(func)) {
return (g:any)=>func.innerFunc("test", g)
}
else {
return (g:any)=>func.innerFunc(1, "test", g)
// ^ -- error here
// TS indicates that narrowed type of innerFunc is
// (property) innerFunc: (arg0: never, arg1: any, c: any) => void
// What is that based on?
}
}
如果我在else语句中显式调用第二个类型防护,它将按预期工作:
function transfomerTwo<U extends UnionFunc<any>>(func:U){
if(isOneArgFunc(func)) {
return (y:any)=>func.innerFunc("test", y)
}
else if(isTwoArgFunc(func)) {
return (z:any)=>func.innerFunc(1, "test", z)
}
else {return func}
}
但是我不知道为什么上面的第一个不起作用?由于某种原因,我假设联合实际上不是二进制的,但是我无法确切地看到else语句之后TS如何或如何为innerFunc提出奇怪的函数签名。
有人可以帮助我理解吗?
完整代码位于this playground.
答案 0 :(得分:1)
以下工作适合您吗?我认为最好将通用类型指定为isOneArgFunc。至少它不再引起任何错误。
function transfomer<T>(func:UnionFunc<T>){
if(isOneArgFunc<T>(func)) {
return (g:any)=>func.innerFunc("test", g)
}
else {
return (g:any)=>func.innerFunc(1, "test", g)
// ^ -- No more error
}
}