【问题标题】:Error 2349 when dealing with union type of generic T and function处理泛型 T 和函数的联合类型时出现错误 2349
【发布时间】:2020-10-11 12:06:18
【问题描述】:

如何修复以下代码以解决 2349?

function fillArray<T>(arr: T[], value: T | ((index: number) => T)): void {
    if (typeof value === 'function') {
        for (let i = 0; i < arr.length; i++) {
            arr[i] = value(i)
        }
    } else {
        arr.fill(value)
    }
}

value(i) 的 TypeScript 报告错误为:

此表达式不可调用。 不是所有类型的成分 '((index: number) => T) | (T & Function)' 是可调用的。

见:Playground Link

【问题讨论】:

    标签: typescript


    【解决方案1】:

    不确定究竟是什么导致了错误(可能与此issue 相关,泛型类型参数变窄)。

    作为一种解决方法,您可以定义和使用custom type guard

    function isFunction<T>(value: T | ((index: number) => T)): value is (index: number) => T {
        return typeof value === 'function';
    }
        
    function fillArray<T>(arr: T[], value: T | ((index: number) => T)): void {
        if (isFunction(value)) {
            for (let i = 0; i < arr.length; i++) {
                arr[i] = value(i)
            }
        } else {
            arr.fill(value)
        }
    }
    

    Playground


    @VLAZ 发现的其他工作选项是使用 instanceof 保护而不是 typeof

    function fillArray<T>(arr: T[], value: T | ((index: number) => T)): void {
        if (value instanceof Function) {
            for (let i = 0; i < arr.length; i++) {
                arr[i] = value(i)
            }
        } else {
            arr.fill(value)
        }
    }
    

    Playground


    另一个可行的选项 - 使数组类型成为泛型参数:

    function fillArray<A extends Array<unknown>>(
        arr: A,
        value: A[number] | ((index: number) => A[number])
    ): void {
        if (typeof value === 'function') {
            for (let i = 0; i < arr.length; i++) {
                arr[i] = value(i)
            }
        } else {
            arr.fill(value)
        }
    }
    

    Playground

    【讨论】:

    • 我认为value instanceof Function 也适用于正确缩小类型。
    • 我也没有。我既无法解释,也找不到原因。我打算将其发布为答案,但由于我无法证明它的合理性,我将其作为评论留下。这很可能是已知问题 in 中的一个错误,这使它正确吗?不确定。或者可能是一些修复并中途修复它。有趣的是typeof value === "function" 也部分有效。在else 中,value 仅被视为T
    • @VLAZ 将数组类型作为泛型参数也可以工作。可能这与链接问题typescriptlang.org/play/index.html#code/… 不完全相关
    • 我能理解的那个。因为A 和函数之间不应该有重叠。我怀疑T 不起作用,因为它可能重叠。然后typeof 没有过滤掉它,但instanceof 过滤掉了,所以我真的不明白发生了什么。我认为两人应该做同样的事情,但不要。对我来说,用户定义的类型保护似乎是实现这一点的最可靠方法。至少那时我希望未来的版本不会破坏它。我怀疑instanceof 可能会倒退。而且我发现它比约束泛型参数更容易阅读。
    猜你喜欢
    • 1970-01-01
    • 2022-01-28
    • 1970-01-01
    • 1970-01-01
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多