添加到JB Nizet 的答案中,并对代码背后的推理进行一些解释。
TypeScript 使用结构类型系统1。这意味着如果它像鸭子一样嘎嘎叫,那么它可以被认为是鸭子(或者更准确地说,与鸭子兼容)。举个例子
class Duck {
quack() { }
}
let duck = {
quack: () => {}
}
由于duck
有一个quack
方法,你可以将它传递给任何期望 a 的东西Duck
,比如
function doQuack(duck: Duck) {
duck.quack();
}
doQuack(duck);
TypeScript 足够聪明,即使我们从未实际创建using的实例,duck
也可以将对象字面量视为 a 。这是因为 的结构足以兼容类型,因为它匹配结构;该结构只是一种方法。Duck
Duck
duck = new Duck()
duck
Duck
quack
如果我们尝试键入duck
as Duck
,但我们没有该quack
方法,那么我们会得到一个编译错误。
let duck: Duck = { // compile error
mooo: () => {}
};
let duck: Duck = {
quack: () => {} // OK
}
话虽如此,以您的示例为例,它HeroSerivce
有两种方法,一种是获取所有英雄,另一种是通过 id 获取英雄。
class HeroService {
getHeroes(): Hero[] { .. }
getHeroById(id: number): Hero { .. }
}
并且HeroComponent
带有一个接受 a 的构造函数HeroService
class HeroComponent {
constructor(heroService: HeroService) {}
}
现在,如果我们尝试通过以下
let mockService = { getHeroes: () => expectedHeroes }
对于HeroComponent
构造函数,我们将得到一个编译错误,因为 与a的结构mockService
不匹配。当结构实际上由两种方法组成时,它只有一种方法,并且.HeroService
getHeroes
getHeroes
getHero
因此,为了强制编译器接受它,我们将其“强制转换”为<HeroService>
.
我们可以通过以下内容(没有“强制转换”)并且它会起作用,因为它与结构匹配。
let mockService = {
getHeroes: () => expectedHeroes,
getHero: (id: number) => null
};
1 - 阅读 TypeScript 文档章节类型兼容性的更多信息