declare关键字的含义是什么?

type Callback = (err: Error | String, data: Array<CalledBackData>) => void;

vs.

declare type Callback = (err: Error | String, data:Array<CalledBackData>) => void;

在TS中找不到解释declare关键字目的的文档。Qué signa ?


当前回答

这里有一个真实的例子。

我有一个使用Webpack热中间件的TypeScript React应用程序。Webpack热中间件不是用TypeScript编写的,而是用老式的JavaScript编写的。所以它没有TypeScript编译器可以检查的类型声明。

当我运行我的代码时,来自Webpack热中间件的对象模块存在,我可以console.log它,尽管它是隐藏在我漂亮的新TypeScript React应用程序中的老式JavaScript。

模块对象也有键,比如module. key。Hot,键可以有值。但是TypeScript设计时编译器(至少在VSCode中)在它下面画了一个红色的曲线,表示属性“hot”不存在。但它确实存在!

为了让TypeScript编译器同意,像这样声明它:

declare let module: any

现有的模块对象,现在有了any类型,这让TypeScript编译器很高兴,红色曲线消失了,现在我可以继续编译并编写其他代码。

如果你删除关键字declare,只写let module: any,它不会编译,而是说'module'已经存在。这就是“ambient”在公认答案中的意思。

其他回答

来自Typescript文档:

Typescript -使用其他JavaScript库

To describe the shape of libraries not written in TypeScript, we need to declare the API that the library exposes. Because most JavaScript libraries expose only a few top-level objects, namespaces are a good way to represent them. We call declarations that don’t define an implementation “ambient”. Typically these are defined in .d.ts files. If you’re familiar with C/C++, you can think of these as .h files. Let’s look at a few examples. Ambient Namespaces The popular library D3 defines its functionality in a global object called d3. Because this library is loaded through a tag (instead of a module loader), its declaration uses namespaces to define its shape. For the TypeScript compiler to see this shape, we use an ambient namespace declaration. For example, we could begin writing it as follows: D3.d.ts (simplified excerpt) declare namespace D3 { export interface Selectors { select: { (selector: string): Selection; (element: EventTarget): Selection; }; } // (...) }

当您导入一些没有声明类型文件的库时,如*.d.ts,使用Delcare关键字

之后vs eslint不检查语法和上下文,会让你通过,如果你默认使用TSC编译器,那就有很好的理由声明删除语法错误

考虑这个场景:您有一个Typescript项目。然后,不管出于什么原因,你决定用JavaScript编写一个模块,并在Typescript代码中使用它。

// getMyName.js
module.exports = function getMyName(name) {
    return name;
}

然后将它导入typescript代码中

// myCode.ts
import getMyName from 'getMyName'; //getMyName is a JS module not typescript

当导入该JS模块时(allowJs编译器选项应该设置为false,否则JS文件将在没有任何类型定义的情况下被解析),Typescript的编译器会抱怨该模块根本不是模块!

找不到模块“/absolute/path/to/getMyName.ts”的声明文件

这是因为Typescript不会自行解析为JS代码。为了避免这个问题,我们应该为JS模块提供类型定义(filename.d.ts)。为此,您可以使用声明和导出。

// getMyName.d.ts
declare function getMyName(name: string): string;

export default getMyName;

之后,当我们导入JS模块时,typescript不会抱怨任何事情,因为它现在可以访问类型了。

这里有一个真实的例子。

我有一个使用Webpack热中间件的TypeScript React应用程序。Webpack热中间件不是用TypeScript编写的,而是用老式的JavaScript编写的。所以它没有TypeScript编译器可以检查的类型声明。

当我运行我的代码时,来自Webpack热中间件的对象模块存在,我可以console.log它,尽管它是隐藏在我漂亮的新TypeScript React应用程序中的老式JavaScript。

模块对象也有键,比如module. key。Hot,键可以有值。但是TypeScript设计时编译器(至少在VSCode中)在它下面画了一个红色的曲线,表示属性“hot”不存在。但它确实存在!

为了让TypeScript编译器同意,像这样声明它:

declare let module: any

现有的模块对象,现在有了any类型,这让TypeScript编译器很高兴,红色曲线消失了,现在我可以继续编译并编写其他代码。

如果你删除关键字declare,只写let module: any,它不会编译,而是说'module'已经存在。这就是“ambient”在公认答案中的意思。

博士TL;

declare用来告诉编译器“这个东西(通常是一个变量)已经存在,因此可以被其他代码引用,也不需要将这条语句编译成任何JavaScript”。

常用用例:

你将网页的引用添加到一个JavaScript文件中,而编译器对此一无所知。也许它是来自其他域的脚本,如“foo.com”。当被求值时,脚本将创建一个带有一些有用API方法的对象,并将其分配给全局作用域中的标识符'fooSdk'。

你希望你的TypeScript代码能够调用fooSdk. dosomething(),但是由于你的编译器不知道fooSdk变量的存在,你会得到一个编译错误。

然后使用declare关键字告诉编译器“相信我,这个变量存在并且具有这种类型”。编译器将使用此语句静态检查其他代码,但不会将其转编译为输出中的任何JavaScript。

declare const fooSdk = { doSomething: () => boolean }

较新的Typescript版本需要稍微不同的语法:

declare const fooSdk : { doSomething: () => boolean }

同样,您可以向类属性添加declare关键字,以告诉编译器不要发出任何会创建此属性的代码,假设您有自己的代码会创建编译器不知道或不理解的属性。

您的具体示例有所不同,因为您声明的是类型,而不是变量,类型已经不会编译到任何JavaScript中。我不知道是否有任何理由声明一个类型。