避免接口和类定义中的字段声明重复

Pee*_*aha 6 typescript typescript-typings

我有一个像这样的界面

interface I {
  a : string;
  b : number;
  c : string;
}

Run Code Online (Sandbox Code Playgroud)

现在我声明一个类,该类将a, b, c根据接口具有公共成员I

所以我声明

class C implements I {
  public a : string;
  public b : number;
  public c : string;
  // and then constructor, other fields, other methods
}
Run Code Online (Sandbox Code Playgroud)

有没有办法避免重复声明字段?即,我希望通过扩展接口来拥有这些字段,而无需实际声明它们。所以我只剩下写一些类似的东西了:

class C implements I {
  // perhaps a magic statement that asserts that C should inherit all members from I
  // and then constructor, other fields, other methods
}
Run Code Online (Sandbox Code Playgroud)

雪上加霜的是,构造函数中存在更多重复,因为我不能仅从满足单行接口的对象I文字中初始化字段

constructor(data : I) {
   this.a = data.a;
   this.b = data.b;
   this.c = data.c;
}
Run Code Online (Sandbox Code Playgroud)

我无法控制接口的定义,我只能控制类的定义(这意味着我不能将接口变成抽象类......)

VLA*_*LAZ 8

是的,这是可能的。它需要一些不直观的代码,但它会正确确保您不会添加冗余代码。

您需要在类定义之外添加以下行:

interface I {
  a : string;
  b : number;
  c : string;
}

interface C extends I {}; //<--- this line 

class C implements I {
  constructor(data : I) {
    this.a = data.a;
    this.b = data.b;
    this.c = data.c;
  }
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

现在,TypeScript 编译器将认为该类C已声明与接口相同的字段I

它的工作原理如下:

  • interface C声明一个名为 的接口C
  • extends I意味着它继承了现有接口的属性I
  • {}只是这个界面的主体C- 它是空的,因为我们不添加或更改任何内容。

就其本身而言,它并不是很令人印象深刻。但是,已经存在一个名为 的类C,因此同名的接口指的是该类具有的相同接口。简单来说,

class A {
    public foo: string;
    constructor(data: string) {
        this.foo = data;
    }
}
Run Code Online (Sandbox Code Playgroud)

在 JavaScript(目标 ES6+)中编译为

class A {
    constructor(data) {
        this.foo = data;
    }
}
Run Code Online (Sandbox Code Playgroud)

删除的信息与 TypeScript 将在编译时使用的类的接口有关,以确保您正确使用该类。例如:

  • 添加或引用未声明的属性
  • foo: string根据其类型使用声明的属性(例如)(例如,不将其视为foo数字)。
  • 使用正确数量和类型的参数调用构造函数

声明与类同名的接口会将声明与类的声明合并。这就是类接口可以被操作的原因。在这种情况下,我们使用extends(这对接口有效)来丰富类定义(仅implements允许)。

作为参考,我从GitHub 上 TypeScript 存储库的问题线程中的评论中获得了该技术。GitHub 问题的标题是“类声明应该隐式实现接口”,评论由 RyanCavanaugh 在 2016 年 2 月 17 日发表:

请注意,在最新版本的 TypeScript 中,您可以使用类/接口合并来执行此操作:

interface Foo {
    a: number;
}

interface Baz extends Foo { }
class Baz {
   constructor() {
       console.log(this.a); // no error here
   }
}
Run Code Online (Sandbox Code Playgroud)

帽子提示@jeffreymorlan 提醒我这一点

[注:发表评论时最新发布的版本是 1.8 Beta ]

  • @sleepwalker实际上[就是这个](https://github.com/microsoft/TypeScript/issues/340#issuecomment-184964440) (2认同)