考虑这个小小的 Typescript 示例:
interface Parent {
name: string;
}
interface Child extends Parent {
name: "Joe";
}
这可行,但我不太明白为什么。
我对继承的理解是,理想情况下,您应该能够这样说:“子级的行为方式与父级相同,再加上一些东西”,因此有“扩展”这个词。但在这种情况下,Parent 允许使用任何字符串作为名称,而 Child 只允许使用特定字符串。因此,Child 缩小了 Parent 的可能性,你不能说,Child 的行为方式与 Parent 的行为方式相同。我在这里考虑的是里氏替换原理。
那么它在 Typescript 中工作的原理是什么?
最佳答案
对于类型,它与可分配性有关。类型的工作方式是子类型应该可以分配给父类型而无需断言。
在这种情况下,子项比父项更具体,因此这是允许的 - "Joe"
是具体的,string
是通用的。它是可赋值的,因为 string
包含字符串的所有可能性,其中包括 "Joe"
。
一般包含特定,但特定不包含一般
因此,您可以将子项分配给父项:
const child: Child = { name: "Joe" };
const parent: Parent = child; // ok, because name being "Joe" is assignable to string
但是您不能将父级分配给子级:
const parent: Parent = { name: "Alex" };
const child: Child = parent; // not ok, because name being string might not be "Joe"
其他示例
这与您可以拥有具有可选属性的父级和具有必需属性的子级的原因相同:
interface Parent {
name?: string;
}
interface Child extends Parent {
name: string;
}
可变性危险
如果使用得当,以这种方式添加限制会非常有用。我偶尔会这样做。
但是,当属性可变时,这是很危险的。如果使用不当,可能会发生以下情况:
const child: Child = { name: "Joe" };
const parent: Parent = child;
parent.name = "Alex";
console.log(child.name); // Alex
这可能就是您考虑 LSP 的原因。为了避免这种危险,可以将对象的属性标记为只读并以不可变的方式使用。
关于inheritance - Typescript - 为什么字符串类型可以被字符串文字覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40977040/