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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14345485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 16:27:55  来源:igfitidea点击:

What's the difference between "declare class" and "interface" in TypeScript

javascripttypescript

提问by Chris

In TypeScript, when creating .d.ts source declaration files, which is preferable and why?

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

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

or

或者

interface Example {
    Method(): void;
}

The differences that I can tell are that interfaces can't have static methods, so you must use a class for that. Both don't product any JS output, so perhaps it doesn't matter?

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

回答by Ryan Cavanaugh

interfaceis for when you simply want to describe the shape of an object. There's no code generation, ever, for interfaces -- they're solely an artifact in the type system. You'll see no difference in the code generation for a class depending on whether or not it has an implementsclause.

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

declare classis for when you want to describe an existingclass (usually a TypeScript class, but not always) that is going to be externally present (for example, you have two .ts files that compile to two .js files and both are included via scripttags in a webpage). If you inherit from a classusing extends(regardless of whether the base type was a declare classor a regular class) the compiler is going to generate all the code to hook up the prototype chain and forwarding constructors and what not.

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

If you try to inherit from a declare classthat should have been an interface, you are going to have a runtime error because that generated code will be referring to an object with no runtime manifestation.

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

Conversely, if you simply implementan interface that should have been a declare class, you're going to have to re-implement all the members yourself and won't be taking advantage of any code re-use from the would-be base class, and functions that check the prototype chain at runtime will reject your object as not actually being an instance of the base class.

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

To get really nerdy, if you have a C++ background, you can roughly think of interfaceas typedefand declare classas an externdeclaration of a constructor that strictly lacks a definition in this compile unit.

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

From a pure consumption side (writing imperative code, not adding new types), the only difference between interfaceand declare classis that you can't newan interface. However, if you intend to extend/implementone of these types in a new class, you absolutely have to have chosen correctly between interfaceand declare class. Only one of them will work.

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

Two rules that will serve you well:

两条规则可以很好地为您服务:

  • Is the name of the type aligning with a constructor function (something invokable with new) that's actually present at runtime (e.g. Dateis, but JQueryStaticis not)? If no, you definitely want interface
  • Am I dealing with a compiled class from another TypeScript file, or something sufficiently similar? If yes, use declare class
  • 类型的名称是否与new运行时实际存在的构造函数(可调用的东西)对齐(例如,Date是,但JQueryStatic不是)?如果没有,你肯定想要interface
  • 我是在处理来自另一个 TypeScript 文件的编译类,还是非常相似的东西?如果,请使用declare class

回答by Fenton

You can implement the interface:

您可以实现接口:

class MyClass implements Example {
    Method() {

    }
}

Whereas the declare classsyntax is really intended to be used to add type definitions for external code that isn't written in TypeScript - so the implementation is "elsewhere".

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

回答by nikk wong

In layman's terms, declareis used in .ts/d.tsfiles to tell the compiler that we should expect the keyword we're declaringto exist in that environment, even if it is not defined in the present file. This will then allow us to have type safety when using the declared object, as the Typescript compiler now knows that some other component may provide that variable.

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

回答by Willem van der Veen

Difference between declareand interfacein TS:

TSdeclareinterfaceTS之间的区别:

declare:

宣布:

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

In the above code declarelets the TS compiler know that somewhere the class Exampleis declared. This does not mean that the class is magically included. You as a programmer are responsible for having the class available when you are declaring it (with the declarekeyword).

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

interface:

界面:

interface Example {
    Method(): void;
}

An interfaceis a virtual construct that only exists within typescript. The typescript compiler uses it for the sole purpose of type checking. When the code is compiled to javascript this whole construct will be stripped out. The typescript compiler uses interfaces in order to check if objects have the right structure.

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

For example when we have the following interface:

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

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

The objects which we define which have this interface type need to match the interface exactly:

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

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