【问题标题】:Figuring out which interfaces a class has implemented in TypeScript找出一个类在 TypeScript 中实现了哪些接口
【发布时间】:2018-04-15 10:33:32
【问题描述】:

我在设计与类和接口的各种关系时遇到了一些问题,因为 TypeScript 不允许像 C# 那样进行某些类型转换。

我当前的层次结构如下:

interface IComponent {}
interface IBehaviour1 {}
interface IBehaviour2 {}
class Component implements IComponent, IBehaviour1 {}
class SpecializedComponent extends Component implements IBehaviour2 {}

在另一个类中,我存储了一个Set<IComponent> 集合,我在其中注册了多个ComponentSpecializedComponent 对象。但是,在一个函数中,我需要遍历所有这些函数并调用 IBehaviour1 特定方法(如果存在)和 IBehaviour2 特定方法(如果存在)。

由于我经常调用此方法,因此我决定创建以设置 Set<IBehaviour1>Set<IBehaviour2> - 每次调用 addComponent 时,我都会对新组件进行适当的分类。

在 C# 中,这看起来像这样:

void AddComponent(IComponent component)
{
    if (component is IBehaviour1)
        behaviour1Components.Add((IBehaviour1)component);
    if (component is IBehaviour2)
        behaviour2Components.Add((IBehaviour2)component);
}

不幸的是,TypeScript 不允许如上所示的特定类型检查/比较,因为 IBehaviour1IBehaviour2IComponent 不兼容。此外,两组并不相交。我很好奇应该如何存储所有组件,以便可以调用所有行为方法(如果存在)。

【问题讨论】:

  • 还没有尝试过任何东西,但是您是否尝试使用像void Add component<T extends IComponent>(component: T) 这样的通用设置来代替?

标签: typescript polymorphism


【解决方案1】:

在 Typescript 中,接口只是一个编译时结构。重要的是您需要使用的方法/字段是否在运行时实际存在于对象上,这就是您应该执行的测试。为了使事情在语法上更令人愉悦,您可以使用类型保护来帮助进行类型推断:

interface IComponent { }
interface IBehaviour1 {
  behaviour1Method(): void
}
interface IBehaviour2 {
  behaviour2Method(): void
}
class Component implements IComponent, IBehaviour1 {
  behaviour1Method(): void { }
}
class SpecializedComponent extends Component implements IBehaviour2 {
  behaviour2Method(): void { }
}

function isIBehaviour1(a: any): a is IBehaviour1 {
  return (a as IBehaviour1).behaviour1Method != null;
}
function isIBehaviour2(a: any): a is IBehaviour2 {
  return (a as IBehaviour2).behaviour2Method != null;
}

class Usage {
  behaviour1Components: IBehaviour1[] = []
  behaviour2Components: IBehaviour2[] = []
  addComponent(component: IComponent): void {
    if (isIBehaviour1(component)) {
      this.behaviour1Components.push(component);
    }
    if (isIBehaviour2(component)) {
      this.behaviour2Components.push(component);
    }
  }
}

【讨论】:

  • 您的建议按预期工作,非常感谢。我对类型保护函数做了一个小改动:function isIBehaviour1<T extends IComponent>(a: T): a is T & IBehaviour1 { return ((a as IComponent) as IBehaviour1).behaviour1Method !== undefined; } - 有什么特别的区别吗?
  • @ChristianIvicevic 该版本应该也可以正常工作,并且如果您需要它也可以保留源类型
  • 我注意到我的版本有一个小问题(它只适用于您的示例中的空 IComponent) - 因为我的 IComponent 有一个 componentFunction() 我的版本有一个错误为 @987654326 @ 不能转换为 IBehaviour1IBehaviour2。最后我不得不使用你的。
  • 您可以转换为any 而不是IComponent 结果可以保持不变,return ((a as any) as IBehaviour1).behaviour1Method !== undefined
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
  • 2012-12-12
  • 2010-11-10
  • 1970-01-01
  • 2021-06-21
  • 2021-07-20
相关资源
最近更新 更多