typescript - Typescript 中与通用容器混淆的错误
问题描述
考虑这段代码:
class Base {}
class Foo<T extends Base> {
constructor(public callback: (data: T) => void) {
}
}
let map: Map<number, Foo<Base>> = new Map();
function rpcCall<T extends Base>(
callback: (data: T) => void,
): void {
map.set(0, new Foo<T>(callback));
}
它给了我这个错误:
type
Foo<T>
的参数不能分配给 type 的参数Foo<Base>
。类型
Base
不可分配给 typeT
。
Base
可分配给 type 的约束T
,但T
可以用不同的约束子类型实例化Base
。
我不明白为什么这不应该工作。错误消息似乎是正确的,但我不明白为什么这是一个错误。我希望 T
被允许成为约束的不同子类型Base
。
此外,这确实有效:
class Base { }
class Foo<T extends Base> {
constructor(public callback: (data: T) => void) {
}
}
class Foo2<T extends Base> {
}
let map: Map<number, Foo<Base> | Foo2<Base>> = new Map();
function rpcCall<T extends Base>(
callback: (data: T) => void,
): void {
map.set(0, new Foo<T>(callback));
}
解决方案
我将在您的代码中添加一些属性来说明这一点。
interface Base {
bar: string;
}
interface Child extends Base {
magic: number;
}
class Foo<T extends Base> {
constructor(public callback: (data: T) => void) {
// '{ bar: string; }' is assignable to the constraint of type 'T',
// but 'T' could be instantiated with a different subtype of constraint 'Base'.
callback({ bar: "sweet" });
}
}
let map: Map<number, Foo<Base>> = new Map();
rpcCall((d: Child) => d.magic);
function rpcCall<T extends Base>(callback: (data: T) => void) {
// 'Base' is assignable to the constraint of type 'T',
// but 'T' could be instantiated with a different subtype of constraint 'Base'
map.set(0, new Foo(callback));
}
哦亲爱的。更多错误!
如您所见,在里面Foo
我试图调用您定义的回调,并传递给它一个 extends 对象Base
,但它向我抛出了一个错误。
如果回调期待 aChild
怎么办?当然,只要关心,任何扩展Base
都很好Foo
,但是你怎么知道回调本身期望什么?
如果你看一下我在rpcCall
哪里合法地给它一个回调期望 a 的用法Child
,我正在尝试使用该属性(在我的界面magic
中标记为必需)。Child extends Base
基本上在某些时候可能会尝试使用不存在的东西Base
。
如果您将泛型替换为简单地Base
会使一些错误消失,但rpcCall((d: Child) => d.magic)
不允许执行类似的操作。如果您不需要这些区域的非基础属性,这对您来说可能没问题。
您提供的第二个版本之所以有效,是因为Foo2
它是一个空类(实际上,泛型完全被忽略了,因为您不使用它)。
一个空类相当于{}
,它基本上接受除null
and之外的所有内容undefined
(据我所知)。当涉及联合类型时,任何“宽松”的参数都将优先于更严格的参数。
以下都是等价的(在这种情况下):
Map<number, Foo<Base> | Foo2<Base>>
Map<number, Foo<Base> | {}>
Map<number, Foo<Foo2<Base>>
Map<number, Foo<{}>
实际上,如果您通过管道传输| any
到任何联合的末尾,则该联合实际上变为any
.
推荐阅读
- javascript - 如何使包含方法检查多个参数?
- android - “ ion-raw ” 不是已知元素
- r - 在 WordPress 上发布 RMarkdown 创建的帖子
- python - 我在 Python 中遇到 TypeError。如何修复“NoneType”对象不可迭代错误?
- c++ - 从 'const int*' 到 'int*' 的无效转换
- asp.net - 如何在 Blazor WebAssembly 的 blazor-error-ui 元素中显示错误详细信息?
- azure-devops - 如何在 Power BI 中为 Azure Devops 中的结果创建测试结果可追溯性报告?
- android - 我可以从 MotionLayout 导出动画吗?
- html - 如何水平居中对齐移动和桌面视图的网页?
- c++ - 如何将 tolow 应用于字符串向量?