typescript - 如何告诉 TypeScript 两个泛型类型是相同的?
问题描述
考虑以下重载函数。
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
,反之亦然。
解决方案
重载函数具有一组调用签名声明,这些声明确定如何调用函数,以及(假设函数已实现而不是仅声明)单个实现。实现签名是不可调用的。
在您的示例代码中,您有一个调用签名
// 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有一个建议这样做,但由于过于复杂而无法实现,因此被关闭。相反,编译器所做的是确保实现签名参数可以处理来自每个调用签名的参数,并确保实现签名返回类型可以处理来自每个调用签名的返回返回类型。也就是说,返回类型可以是所有调用签名的返回类型的并集。这不是类型安全的(因为您可能会为特定的调用签名返回错误的类型),但很方便。
不管好坏,这种松散的检查是 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;
}
它无论如何都不是完美的,但如果我们想把这两个独立的行为放到一个重载函数中,它可能是我们能得到的最好的。
推荐阅读
- javascript - 无法在 Angular 模板中呈现内容
- sql - SQL Server:将数百万行从一个视图移动到另一个表
- c# - 功能
事件和头痛 - c++ - 是否有用于确定不超过数字 x 的最大元素的 std::set 函数?
- java - 以递归方式使用 java 8 CompletableFuture
- python - 使用 django 捕获网络摄像头图像并上传数据库
- linux - 让特定用户完全访问我拥有的任何东西 linux
- testing - 我可以使用嵌入式 iframe 吗?
- mysql - 我需要获取用户首次付款日期和用户注册日期之间的差值
- javascript - 每个生成的用户,都会生成两个新的 JS