首页 > 解决方案 > 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}
}

但我不明白为什么上面的第一个不起作用?由于某种原因,我假设联合并不是真正的二进制,但我无法确切地看到 TS 如何或如何在 else 语句之后为 innerFunc 提出奇怪的函数签名。

谁能帮我理解这一点?

完整的代码在这个操场上。

标签: typescript

解决方案


以下内容对您有用吗?我认为最好将泛型类型指定为 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
    }
}

推荐阅读