javascript - 是否可以将 TypeScript 接口(interface)识别为其继承的接口(interface)?

标签 javascript typescript inheritance interface

我有一个 TypeScript 接口(interface),可以通过许多其他接口(interface)进行扩展。例如,称它为 Parent 并说 2 个接口(interface)扩展 Parent 并称为 ChildAChildB。实际上,有更多的 child 继承自 Parent

interface Parent {
  sharedProp: string;
}

interface ChildA extends Parent {
  uniqueChildAProp: string;
}

interface ChildB extends Parent {
  uniqueChildBProp: string;
}

有没有办法让我有另一个接口(interface) Grandparent 定义类似于如下:

interface Grandparent {
  children: Parent[];
}

children 数组中的元素可以是 ChildAChildB(或任何其他扩展 Parent 的接口(interface)>)?

这将是一个有效的祖 parent :

const concrete: Grandparent = {
  children: [
    {
      sharedProp: 'fooA',
      uniqueChildAProp: 'barA'
    },
    {
      sharedProp: 'foo',
      uniqueChildBProp: 'barB'
    }
  ]
}

我想避免合并 ChildA、ChildB 等类型,因为 Parent 可能有很多继承者。

最佳答案

如果你想限制 Grandparentchildren 属性为 known Parent 扩展的数组>,那么联合是唯一的方法。另一方面,如果您希望接受 Parent所有结构兼容 扩展,甚至是尚未声明的扩展...那么您不需要完全改变定义。

您现有的 Grandparent 定义已经允许children 属性的元素成为Parent 或任何子类型Parent 的,例如 ChildAChildB。您可能遇到的问题是,当您像使用 concrete 一样使用对象文字时,编译器会执行 excess property checking并提示它不期望的属性:

const concrete: Grandparent = {
  children: [
    {
      sharedProp: 'fooA',
      uniqueChildAProp: 'barA' // error!
    },
    {
      sharedProp: 'foo',
      uniqueChildBProp: 'barB' // error!
    }
  ]
};

但这并不意味着您不能传递ChildAChildB;这只是意味着您需要告诉编译器您打算拥有一个ChildAChildB 以便属性并不意外:

const cA: ChildA = { sharedProp: 'fooA', uniqueChildAProp: 'barA' };
const cB: ChildB = { sharedProp: 'foo', uniqueChildBProp: 'barB' };
const concrete1: Grandparent = { children: [cA, cB] };

或者您可以通过许多其他方式重构来安抚编译器并避免过多的属性检查:

const children = [
  {
    sharedProp: 'fooA',
    uniqueChildAProp: 'barA'
  },
  {
    sharedProp: 'foo',
    uniqueChildBProp: 'barB'
  }
];
const concrete2: Grandparent = { children }; // okay

如果你想允许 Parent 的子类型而不提示对象文字中的额外属性,你可能会决定使用 index signature因为对象文字与适当的索引签名隐式兼容。像这样:

interface AnyParent extends Parent {
  [k: string]: unknown;
}

interface Grandparent2 {
  children: AnyParent[];
}

const concrete3: Grandparent2 = {
  children: [
    {
      sharedProp: 'fooA',
      uniqueChildAProp: 'barA'
    },
    {
      sharedProp: 'foo',
      uniqueChildBProp: 'barB'
    }
  ]
}; // okay

这适用于您的示例代码。不过要小心;根据 microsoft/TypeScript#15300 , interface 类型与索引签名隐式兼容,因此使用显式 ChildA 注释将不再有效:

const childA: ChildA = { sharedProp: "", uniqueChildAProp: "" };
const oops: Grandparent2 = { children: [childA] }; // error!

因此,如果您只关心对象文字和类型别名而不关心接口(interface),那么索引签名确实是可取的。因此,我可能会建议第一个选项并重构、注释或 assert您有意添加额外的属性。


好的,希望对你有帮助;祝你好运!

Playground link to code

关于javascript - 是否可以将 TypeScript 接口(interface)识别为其继承的接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62963660/

相关文章:

javascript - 从 WebView 中的页面在外部浏览器中打开链接

angular - Angular 6 项目中 2 tslint.json 文件的使用

typescript - 如何在 Typescript 中的两个不同文件中正确导入相同的命名空间

javascript - 如何将 javascript 日期转换为 GMT 毫秒?

javascript - 循环在所有 promise 响应完成之前完成

javascript - 将值从一种模式传递到另一种模式

java - Java中有类似JavaScript的 "prototype"的东西吗?

c++ - 多重继承类的复制构造函数

c++ - 在 C++ 中继承 C 结构并将其传递回 C 库是否安全?

javascript - 注入(inject)的 SVG 丢失尺寸