【发布时间】:2021-12-04 06:38:58
【问题描述】:
说,我有一个这样的类,TypeScript 对此并不满意:
class Foo extends ThirdPartyLibrary {
animal!: Animal;
bar(): void {
this.animal.quack(); // Method `quack` does not exist on type `Animal` ????
}
}
解决此问题的官方方法似乎是使用临时类型缩小功能:
class Foo extends ThirdPartyLibrary {
animal!: Animal;
bar(): void {
function isDuck(maybeDuck: unknown): maybeDuck is Duck {
return maybeDuck?.look === 'ducky' && maybeDuck?.voice === 'quacky';
}
if (!isDuck(this.animal)) {
throw new Error('Expected argument to be a duck');
}
this.animal.quack();
}
}
在某些情况下,这种运行时检查是多余的。例如,当使用类型不佳的第三方库时,我不想在运行时测试该库并编写所有样板代码。
相反,我想写得越短越好。
到目前为止,我最好的尝试是使用as 类型转换将变量重新分配给另一个变量:
class Foo extends ThirdPartyLibrary {
animal!: Animal;
bar(): void {
const animal = this.animal as unknown as Duck;
animal.quack(); // Now TypeScript knows that this animal can quack
}
}
但我不需要那个变量!我只需要 TypeScript 静态知道类型,我不想声明任何运行时变量或 if 子句或抛出的错误。
我正在成像这样的东西:
class Foo extends ThirdPartyLibrary {
animal!: Animal;
bar(): void {
this.animal is Duck; // Narrow down the type without boilerplate
this.animal.quack();
}
}
我只想让 TypeScript 静态地知道在代码中这个变量/属性肯定是特定类型的。我该怎么做?
对我不起作用的解决方案:
-
将
animal属性键入为Duck:class Foo extends ThirdPartyLibrary { animal!: Duck; }这个解决方案对于我的简单示例来说是最合理的,但这只是我想出的一个最小的人工示例。
想象
Foo类比这更复杂:this.anmial被多次使用,大多数时候它可以是任何Animal。只有在代码中的这个特定点,它才能确定是鸭子。 -
使用内联类型转换:
(this.animal as unknown as Duck).quack()。这行得通,但是当你需要对这种动物做不止一件鸭子的事情时,这种方法会变得很烦人:
(this.animal as unknown as Duck).quack(); (this.animal as unknown as Duck).waddle(); (this.animal as unknown as Duck).awwYiss("Motha. Funkin. Bread crumbs!"); -
修复第三方库的类型。假设这些类型真的很复杂,而您没有能力深入研究它们。
【问题讨论】:
标签: typescript typeguards type-narrowing