Typescript-类型防护不会缩小与泛型类型和函数的并集

时间:2020-09-08 16:19:01

标签: typescript

我有两个使用以下方法的名义上的类型的函数(抛开我为什么要这样做的方式-简化此示例以试图阐明我的问题):

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.

1 个答案:

答案 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
    }
}