typescript - 派生类是否实现了 Typescript 中基类的接口
问题描述
派生类是否实现了基类的接口?
例子:
interface IBase {
controls : { [key: string] : number }
}
class BaseClass implements IBase {
controls = {};
}
class TestClass extends BaseClass {
controls = {test:'a'};
}
当接口声明它应该是数字时,在派生类中将控件值设置为字符串时,上述内容不会抱怨。
如果我在派生类中将控件设置为 null,它会抱怨:
类型“null”不可分配给类型“{}”
在每个派生类和类中实现接口的正确方法是什么?
解决方案
当一个类implements
成为接口时,它实际上并不影响类的类型。编译器检查类是否与接口兼容,但它不使用接口作为上下文来为类的成员提供类型。如果您编写class Foo implements Bar {...}
并且没有编译器错误,那么编译器会将其视为与您遗漏implements Bar
并仅编写class Foo {...}
. 有关详细信息,请参阅microsoft/TypeScript#32082和其中链接的问题。
SoBaseClass
的controls
属性被推断为具有空对象类型{}
。您可能期望BaseClass
' 的controls
属性为 type { [key: string] : number }
,但这不会发生,因为此类信息仅来自 子句,在为' 的成员implements IBase
提供类型时会忽略该子句。BaseClass
如果您想查看实现类或子类具有特定类型的属性,您应该注释它们:
class BaseClass implements IBase {
controls: { [key: string]: number } = {}; // annotated
}
class TestClass extends BaseClass {
// you might also want to annotate this, depending on intent
controls = { test: 'a' }; // error!
}
同样重要的是要注意,无论好坏,TypeScript 的类型系统并不完全健全;TypeScript 允许分配不一致的地方有一些“漏洞” 。
在健全的类型系统中,子类型应该是可传递的;这意味着,对于任何类型A
, B
, and C
, if A extends B
and B extends C
, then A extends C
。虽然这在 TypeScript 中很常见,但有时会被违反。这就是您的示例中发生的情况:TestClass extends BaseClass
, 和BaseClass extends IBase
, 但TestClass
不扩展IBase
.
如果我们创建一个VerifyExtends<T, U>
只编译 if的辅助类型函数T extends U
,我们可以见证子类型化的这种不传递性:
type VerifyExtends<T extends U, U> = void;
type AB = VerifyExtends<TestClass, BaseClass> // okay
type BC = VerifyExtends<BaseClass, IBase> // okay
type AC = VerifyExtends<TestClass, IBase> // error!
TestClass extends BaseClass
因为controls
in 的属性有一个在( )TestClass
中没有提到的额外属性,并且允许您通过添加属性来扩展对象类型。BaseClass
{}
并且BaseClass extends TestClass
因为它的controls
属性{}
具有与索引签名冲突的属性(它根本没有属性)......并且 TypeScript 将为此类类型提供隐式索引签名。
但当然,TestClass
不会扩展IBase
,因为额外的属性和隐式索引签名不是相互一致的。所以我们有奇怪的地方。
在你的情况下,我可能会建议明确的注释,因为这是你的意图。但是你迟早会遇到不健全的,你应该为此做好准备。
推荐阅读
- java - 将公共方法转换为私有方法
- python - peewee 表的有效插入权限
- java - IST(印度标准时间)的 LocalDateTime 与 ZoneOffset 以更清洁的方式
- google-maps - “未处理的异常:NoSuchMethodError:在 null 上调用了 getter 'iterator'。” 当我在颤振中使用 google_maps_polyline 插件时抛出
- java - How can I make my robot turn 90 degree to the right?
- c++ - 如何避免在 cmake 中自动链接 Qt5 库?
- docker - Why portainer can not run successfully in docker of windows server 2016?
- php - 在函数内部调用函数时出错
- python - 使用 Pandas pd.DateOffset 查找随机日期前一个月的第一天
- php - PHP:“没有这样的文件或目录”但文件存在