在 TypeScript 中,当创建 .d.ts 源声明文件时,哪个更可取,为什么?
declare class Example {
public Method(): void;
}
或者
interface Example {
Method(): void;
}
我可以说的区别是接口不能有静态方法,所以你必须为此使用一个类。两者都不产生任何 JS 输出,所以也许没关系?
interface
适用于您只想描述对象形状的情况。从来没有为接口生成代码——它们只是类型系统中的一个工件。根据是否有 implements
子句,您将看到类的代码生成没有区别。
declare class
用于当您要描述将在外部存在的 现有 类(通常是 TypeScript 类,但并非总是如此)时(例如,您有两个 .ts 文件编译为两个 .js 文件,两者都通过网页中的 script
标记包含)。如果您使用 extends
从 class
继承(无论基类型是 declare class
还是常规 class
),编译器将生成所有代码以连接原型链和转发构造函数,并且什么不是。
如果您尝试从应该是接口的 declare class
继承,您将遇到运行时错误,因为生成的代码将引用没有运行时表现形式的对象。
相反,如果您只是 implement
一个应该是 declare class
的接口,您将不得不自己重新实现所有成员,并且不会利用任何代码重用的优势 -是基类,并且在运行时检查原型链的函数将拒绝您的对象,因为它实际上不是基类的实例。
如果你有 C++ 背景,你可以粗略地认为 interface
为 typedef
,declare class
为构造函数的 extern
声明,该声明在此编译单元中严格缺乏定义。
从纯粹的消费方面来看(编写命令式代码,而不是添加新类型),interface
和 declare class
之间的唯一区别是您不能 new
一个接口。但是,如果您打算在新的 class
中extend
/implement
其中一种类型,则绝对必须在 interface
和 declare class
之间正确选择。只有其中一个会起作用。
两条规则会很好地为您服务:
类型的名称是否与运行时实际存在的构造函数(可以用 new 调用的东西)对齐(例如 Date 是,但 JQueryStatic 不是)?如果没有,你肯定想要接口
我是在处理来自另一个 TypeScript 文件的编译类,还是类似的东西?如果是,请使用声明类
您可以实现接口:
class MyClass implements Example {
Method() {
}
}
而 declare class
语法实际上旨在用于为不是用 TypeScript 编写的外部代码添加类型定义 - 所以实现是“其他地方”。
通俗地说,declare
在 .ts
/d.ts
文件中用于告诉编译器我们应该期望关键字 we're declaring
存在于那个环境中,即使它没有在当前文件中定义.这将允许我们在使用声明的对象时具有类型安全性,因为 Typescript 编译器现在知道其他一些组件可能会提供该变量。
TS中声明和接口的区别:
宣布:
declare class Example {
public Method(): void;
}
在上面的代码中,declare
让 TS 编译器知道在某处声明了类 Example
。这并不意味着该类被神奇地包含在内。作为程序员,您有责任在声明类时(使用 declare
关键字)使该类可用。
界面:
interface Example {
Method(): void;
}
interface
是仅存在于 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',
}
new
运算符。但是,接口可以具有构造签名,这意味着您可以对接口类型的值调用new
运算符。这与class
的工作方式非常不同,其中构造签名位于类型名称本身而不是该类型的表达式。