inheritance - Typescript - 为什么字符串类型可以被字符串文字覆盖

标签 inheritance typescript

考虑这个小小的 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/

相关文章:

javascript - JavaScript 中仅继承部分父构造函数参数

c++ - 使用基本模板标识符时继承

javascript - 我可以在 Node.js/Express 中动态导入 TypeScript 模块吗?

typescript - 从 Redux Toolkit 的 createSlice 获取 Action 类型

javascript - 动态渲染复选框并处理更改事件: React+Typescript

java - 如何将这种多重继承转换为Java中的接口(interface)?

c++ - 派生运算符 < 接收 Base 对象作为参数

c++ - C++-派生类构造函数的行为

javascript - Ionic2:Ion Infinite 滚动条在 iPhone 中不起作用

asp.net - typescript 在构建时编译不起作用