【问题标题】:Class vs Interface as type in Typescript [duplicate]类与接口作为Typescript中的类型[重复]
【发布时间】:2020-04-09 11:50:17
【问题描述】:

我最近遇到了这个问题,我不确定是使用接口还是类来定义特定类型。

注意:这个问题不是询问classinterface之间的区别

例如,给定这个类和接口

interface IMyClass {
  foo: string;
  bar: () => string;
}

class MyClass implements IMyClass {
  foo = 'foo';
  bar() {
    return 'bar';
  }
}

我会使用类或接口作为函数参数中的类型。

选项 A - 使用 class 作为类型

function identityByClass(value: MyClass): MyClass {
  return value;
}

选项 B - 使用 interface 作为类型

function identityByInterface(value: IMyClass): IMyClass {
  return value;
}

从我的角度来看,我认为两者都可以,但我更喜欢使用类来避免同步接口上的所有方法/属性。我认为接口只是一个类必须遵守的模板/契约。

但是,就我而言,大多数时候,该类通常会添加更多不在接口定义中的方法/属性。

举个例子,下面这个类。

class MyClassPlus implements IMyClass {
  foo = 'foo';
  bar() {
    return 'bar';
  }
  doMore() {
    console.log('more stuff here!');
  }
}

在这种情况下,我不能再交替使用这两者。

任何指向最佳实践的链接也很好。谢谢。

【问题讨论】:

  • 一般如果使用接口,你不用管MyClassPlus有更多的功能吧? , 因为系统是依赖接口而不是MyClassPlus。如果是,你关心它,问题可能是如何为你的系统“设计”一个更通用的界面。
  • 嘿@TimChang!对了,就是这个问题。一旦我在接口上定义的基础上添加到类中,如果我想访问那些添加的方法或属性,我必须使用该类。问题是是同步接口还是只使用类作为增强类的类型。
  • 可能你同时有不同的行为?如果这是你的情况,你可以定义两个接口来处理void DoSome<T>(T myclass) where T : IMyClassA , IMyClassB ,因为你拆分了接口,所以你不能将所有 MyClassPlus 方法/属性同步到一个接口。

标签: typescript oop typescript-typings


【解决方案1】:

我不确定是否使用接口或类来定义特定类型。

类和接口都创建一个类型,因此原则上它们可以互换使用。正如您所指出的,接口就像一个公共合同,而一个类实现了这个合同。

但请考虑以下情况:

  1. 如果您需要更改MyClass,怎么办?
  2. MyClass 暴露了更多的实现细节,它是一个类类型。

MyClass 的重构的新类型签名可能不再有效地用作函数 identityByClass 中的函数参数。所以你需要重构所有消费者 - 呃......使用separate type interface,这不太可能发生。

第 2 点的示例:客户可以想出获取 MyClass 的静态属性的想法(接口不会通过隐藏实现细节来使其显而易见):

class MyClass {
  static baz(){}
  foo = 'foo';
}

function identityByClass(value: MyClass) {
  console.log((value.constructor as any).baz) // function baz()
  // there we go. do something with static baz() method of MyClass
}

顺便说一句:这不仅仅是关于接口和类类型。 Type aliases 提供强大的功能,如映射或条件类型、联合等,并且大多数时候可以用于支持接口。

但是,就我而言,大多数时候,该类通常会添加更多不在接口定义中的方法/属性。

您不需要同步类和接口类型。为了保留它DRY,我想到了两个选择:

  1. Interfaces can extend class type definitions,去掉多余的声明。
  2. 只选择消费者需要的类属性。

我更喜欢第二点,因为它遵循Information HidingLoose coupling 等设计原则。示例:

class MyClass {
  foo = 'foo';
  tooMuchDetail = "hide me"
}

// just pick, what we need (foo here)
type OnlyNeededProps = Pick<MyClass, "foo">

function doSomethingWithFoo(a: OnlyNeededProps) {
  a.foo
  a.tooMuchDetail // error, unknown (OK)
}

doSomethingWithFoo(new MyClass())

【讨论】:

  • 感谢所有这些信息和所有链接!特别是关于界面隔离原则。 static 属性也很有趣。
【解决方案2】:

使用接口定义类型获得的一个好处是接口本身在编译后就被消除了。这减少了应用程序的整体膨胀,这是在这种情况下使用接口的有力论据。

您可能会发现这很有用:https://jameshenry.blog/typescript-classes-vs-interfaces/

【讨论】:

  • 但在这个问题中,选择是在拥有一个类与拥有一个类一个接口之间。
猜你喜欢
  • 2018-09-22
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 2017-05-28
  • 2021-10-29
  • 1970-01-01
  • 2021-06-19
相关资源
最近更新 更多