TypeScript 中“声明类”和“接口”的区别是什么

在 TypeScript 中,当创建. d.ts 源声明文件时,哪个更好? 为什么?

declare class Example {
public Method(): void;
}

或者

interface Example {
Method(): void;
}

我可以说明的区别是接口不能有静态方法,因此必须使用类来实现这一点。两者都不产生任何 JS 输出,所以也许这并不重要?

65447 次浏览

您可以实现接口:

class MyClass implements Example {
Method() {


}
}

declare class语法实际上是用来为不是用 TypeScript 编写的外部代码添加类型定义的——所以实现是“其他地方”。

interface用于描述物体的形状。接口永远不会生成代码——它们只是类型系统中的一个构件。根据类是否具有 implements子句,您将看不到类的代码生成有什么不同。

declare class用于描述将要外部存在的 存在类(通常是 TypeScript 类,但并非总是如此)(例如,您有两个 存在类)。它的文件编译成两个。Js 文件,两者都是通过网页中的 script标签包含的)。如果你使用 extendsclass继承(不管基类型是 declare class还是常规 class) ,编译器会生成所有代码来连接原型链和转发构造函数等等。

如果您试图从应该是接口的 declare class继承,那么将会出现运行时错误,因为生成的代码将引用没有运行时显示的对象。

相反,如果你只是简单地使用 implement接口,那么你必须自己重新实现所有的成员,并且不能利用基类的代码重用,在运行时检查原型链的函数会拒绝你的对象,因为它实际上不是基类的实例。

如果您有一个 C + + 背景,那么可以将 interface粗略地想象为 typedef,而将 declare class想象为构造函数的 extern声明,该构造函数在这个编译单元中严格缺乏定义。

从纯消费的角度来看(编写命令式代码,而不是添加新类型) ,interfacedeclare class之间的唯一区别是您不能使用 new接口。然而,如果你打算在一个新的 class中使用 extend/implement,你必须在 interfacedeclare class之间做出正确的选择。只有一个能用。

两条对你有用的规则:

  • 类型的名称是否与运行时实际存在的构造函数(new可调用的函数)对齐(例如,Date是,但 JQueryStatic不是) ?如果 没有,你一定要 interface
  • 我处理的是来自另一个 TypeScript 文件的编译类,还是类似的东西? 如果是 是的,请使用 declare class

通俗地说,declare.ts/d.ts文件中用于告诉编译器,我们应该期望我们是 declaring的关键字存在于该环境中,即使它没有在当前文件中定义。这将允许我们在使用声明的对象时具有类型安全性,因为 Type 脚本编译器现在知道某些其他组件可能提供该变量。

declareinterface在 TS 中的区别:

声明:

declare class Example {
public Method(): void;
}

在上面的代码中,declare让 TS 编译器知道在某个地方声明了类 Example。这并不意味着神奇地包含了该类。作为程序员,在声明该类时(使用 declare关键字) ,您需要负责该类的可用性。

界面:

interface Example {
Method(): void;
}

interface是只存在于类型脚本中的虚构造。类型脚本编译器使用它的唯一目的是进行类型检查。当代码被编译成 javascript 时,整个结构将被剥离出来。类型脚本编译器使用接口来检查对象是否具有正确的结构。

例如,当我们有以下接口时:

interface test {
foo: number,
bar: string,
}

我们定义的具有这种接口类型的对象需要与接口完全匹配:

// perfect match has all the properties with the right types, TS compiler will not complain.
const obj1: test = {
foo: 5,
bar: 'hey',
}