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

IT技术 javascript typescript
2021-02-27 04:18:33

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

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

或者

interface Example {
    Method(): void;
}

我能说的区别是接口不能有静态方法,所以你必须为此使用一个类。两者都不产生任何 JS 输出,所以也许这无关紧要?

4个回答

interface当您只想描述对象的形状时。从来没有接口的代码生成——它们只是类型系统中的一个工件。根据类是否有implements子句,您不会看到类的代码生成有什么不同

declare class用于描述将在外部存在现有类(通常是 TypeScript 类,但并非总是如此)时(例如,您有两个 .ts 文件编译为两个 .js 文件,并且都通过script标签包含在内)在网页中)。如果您从classusing继承extends(无论基类型是 adeclare class还是常规类型class),编译器将生成所有代码以连接原型链和转发构造函数以及其他什么不是。

如果您尝试从本declare class应是接口的a 继承,则会出现运行时错误,因为生成的代码将引用没有运行时表现形式的对象。

相反,如果你只是implement一个应该是 a 的接口declare class,你将不得不自己重新实现所有成员,并且不会利用任何来自潜在基类和函数的代码重用在运行时检查原型链将拒绝您的对象,因为它实际上不是基类的实例。

要获得真正的书呆子,如果你有一个C ++背景,你可以大致认为interfacetypedefdeclare class作为extern一个构造函数的声明缺乏严格在此编译单元的定义。

从纯消费方面(编写命令式代码,不添加新类型)来看interface之间的唯一区别declare class是您不能new成为接口。但是,如果你打算extend/implement这些类型在新的一个class,你绝对得有间正确地选择interfacedeclare class只有其中之一会起作用。

两条规则对你很有帮助:

  • 类型的名称是否与new运行时实际存在的构造函数(可调用的东西对齐(例如,Date是,但JQueryStatic不是)?如果没有,你肯定想要interface
  • 我是在处理来自另一个 TypeScript 文件的编译类,还是非常相似的东西?如果,请使用declare class
您实际上可以在typescript中新建一个界面。唯一的限制是继承。
2021-05-05 04:18:33
您不能new在接口类型上调用运算符。但是,接口可以具有构造签名,这意味着您可以new对接口类型的值调用运算符。这与工作方式非常不同class,构造签名位于类型名称本身而不是该类型的表达式上。
2021-05-06 04:18:33
如果您采用向接口添加构造函数的方法,它应该是接口的唯一成员,类的“静态”除外。不要将构造函数的接口和构造的对象的接口结合起来。如果你这样做,类型系统会允许像这样的愚蠢行为:new (new x()),其中 x:接口。
2021-05-15 04:18:33

您可以实现接口:

class MyClass implements Example {
    Method() {

    }
}

declare class语法实际上旨在用于为不是用 TypeScript 编写的外部代码添加类型定义 - 因此实现是“其他地方”。

所以你建议应该使用声明类来描述不是用 TypeScript 编写的代码?我会假设是这种情况,但是在签入的 jquery.d.ts 文件中,JQueryStatic 是一个由以下实现的接口:declare var $ : JQueryStatic 我本来希望这是声明 class $ { public static ... }
2021-04-19 04:18:33
说得通。也许这就是原因。
2021-05-09 04:18:33
我能想到的唯一原因是如果您不希望人们扩展该类 - 使用接口意味着您必须提供整个实现。
2021-05-10 04:18:33
好的,所以我试图指向另一个 JS 库中的声明,所以我绝对需要声明。代码在一些库函数(类)上使用了静态 - 到目前为止,我还没有看到在声明文件中表达的静态属性或方法。哦,我应该使用命名空间还是module?
2021-05-11 04:18:33

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

如果在当前文件中没有定义,我们如何找到impl代码在哪里?
2021-05-07 04:18:33

TSdeclareinterfaceTS之间的区别

宣布:

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

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

界面:

interface Example {
    Method(): void;
}

Aninterface是一种仅存在于typescript中的虚拟结构。typescript编译器仅将其用于类型检查。当代码被编译为 javascript 时,整个构造将被剥离。typescript 编译器使用接口来检查对象是否具有正确的结构。

例如,当我们有以下界面时:

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',
  }