typescript - 如何告诉 TypeScript 两个泛型类型相同?

标签 typescript overloading

考虑以下重载函数。

function scan<A>(this: A[], f: (a: A, x: A) => A): A[];
function scan<A, B>(this: A[], f: (a: B, x: A) => B, init?: B): B[] {
    if (init === undefined) {
        const result = [this[0]];
        for (let i = 1; i < this.length; i++) {
            result.push(f(result[i - 1], this[i]));
        }
        return result;
    }

    const result = [init];
    for (let i = 0; i < this.length; i++) {
        result.push(f(result[i], this[i]));
    }
    return result;
}

请注意,当未提供 init 时,泛型类型 B 应与 A 相同。我如何将其告诉 TypeScript?目前,TypeScript 提示 A 无法分配给 B,反之亦然。

最佳答案

overloaded function有一组调用签名声明,它们确定如何调用该函数,以及(假设该函数已实现而不仅仅是声明)单个实现。实现签名不可调用


在您的示例代码中,您有一个调用签名

// call signature
function scan<A>(this: A[], f: (a: A, x: A) => A): A[];

和实现

// implementation
function scan<A, B>(this: A[], f: (a: B, x: A) => B, init?: B): B[] {
    /* snip */
}

但这似乎不是你想要的。您确实希望这些签名都是调用签名,如下所示:

// call signatutes
function scan<A>(this: A[], f: (a: A, x: A) => A): A[];
function scan<A, B>(this: A[], f: (a: B, x: A) => B, init?: B): B[];

// implementation
function scan(...) {

所以问题是:实现签名应该是什么?


TypeScript 的编译器无法通过单独检查每个调用签名来检查实现。有人建议这样做 microsoft/TypeScript#13235 ,但由于实现起来过于复杂而被关闭。相反,编译器所做的是确保实现签名参数可以处理来自每个调用签名的参数,并确保实现签名返回类型可以处理每个调用签名的返回返回类型。也就是说,返回类型可以是 union所有调用签名的返回类型。这不是类型安全的(因为您可能会为特定调用签名返回错误的类型),但很方便。

无论好坏,这种松散的检查都是 TypeScript 重载实现的工作方式。所以在编写重载函数时需要小心。


无论如何,这意味着实现需要像这样:

// implementation signature
function scan<A, B>(this: A[], f: (a: B | A, x: A) => A, init?: B | A) {
    if (init === undefined) {
        const result = [this[0]];
        for (let i = 1; i < this.length; i++) {
            result.push(f(result[i - 1], this[i]));
        }
        return result;
    }

    const result = [init];
    for (let i = 0; i < this.length; i++) {
        result.push(f(result[i], this[i]));
    }
    return result;
}

无论如何它都不完美,但如果我们想将这两个单独的行为放入一个重载函数中,它可能是我们能得到的最好的结果。

Playground link to code

关于typescript - 如何告诉 TypeScript 两个泛型类型相同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67732028/

相关文章:

c++ - 我应该如何制作功能 curry ?

typescript - 不能将 new 与表达式 typescript 一起使用

node.js - 使用 Typescript 向 expressjs 中的 req 对象添加属性

json - Angular 2 - 从 json 文件中获取数据

c++ - 运营商重载奇怪的输出

javascript - 基本类型字符串的 TypeScript 重载方法

typescript - 间接引用远程 Javascript URL

javascript - TypeScript 泛型的优势

list - 重载 "zipWith"支持嵌套列表

c# - 仅基于返回类型重载