“export declare class Actions”中的“declare”有啥作用?

Posted

技术标签:

【中文标题】“export declare class Actions”中的“declare”有啥作用?【英文标题】:What does 'declare' do in 'export declare class Actions'?“export declare class Actions”中的“declare”有什么作用? 【发布时间】:2016-05-03 09:05:42 【问题描述】:

为什么我们需要在语句中使用declare

export declare class Actions 
    ...

【问题讨论】:

Whats the difference between "declare class" and "interface" in TypeScript的可能重复 【参考方案1】:

declare 在打字稿中:

typescript 中的 declare 关键字有助于告诉 typescript 编译器 声明 是在其他地方定义的(在外部 javascript 文件或运行时环境的一部分中编写的地方)。

假设我们在其他地方声明了一个名为 foo 的变量。当我们尝试引用该变量时,打字稿编译器会抛出一个错误:

foo = 'random'; // Error: 'foo' is not defined

我们可以使用declare 关键字来解决这个问题:

declare var foo: string;
foo = 'random';  // no error anymore

这会产生以下后果:

foo 实际上没有在其他任何地方声明,并且我们尝试使用该变量时,可能会发生运行时错误。因此,仅当您知道该变量此时可用时才使用 declare 关键字。 因为我们知道类型,所以我们(可能)可以访问我们的 IDE Intellisense。 因为我们知道类型,所以 typescript 编译器可以在编译时检查类型,如果我们在某些场景中使用了错误的类型,它会警告我们。

【讨论】:

【参考方案2】:

在这种特定情况下的 declare 关键字:

export declare class Actions 
    ...

... 显然没用,我认为 TypeScript 应该考虑将其作为错误(我不知道是否有隐藏的原因)。如果你声明一个类,你永远不需要导入它。如果您导出一个期望有人导入它的类,则不需要声明它。并且因为您正在声明此类,根据定义,此类应该无需导入即可使用。但是,当您export declare 一个类时,情况并非如此。您需要导入才能使用。

TL;DR

export declare class Actions 
    ...

一样
declare class Actions 
    ...

【讨论】:

我觉得它们不一样,前者需要和import一起使用,后者不需要 另外,声明不会破坏 .d.ts 文件的全局范围,而 export 会...(声明不会使文件成为模块)【参考方案3】:

declare - 没有任何导入或导出关键字 - 定义由 TypeScript 自动选择的声明文件,这是向遗留模块添加类型的有用功能(没有 TypeScript 定义的 npm 安装包)。

import / export 是使用模块的正确方法,所有内容都需要手动(我觉得有点乏味)导入,要么是逻辑,要么是定义。

作为一个实际用例,export declare 允许您避免导出所有子元素,例如:

export declare namespace Redux 
    namespace Store 
        interface Definition  ... 
    

这可能比以下内容更容易阅读:

export namespace Redux 
    export namespace Store 
        export interface Definition  ... 
    

两种情况下的外部导入都是相同的(例如import Redux from 'definitions/redux';),我不知道这是否是好的做法,但我觉得它很整洁! ^^

请务必记住,向文件添加 importexport 会将其提升为模块,因此 declare 范围将不再处于全局级别。

PS,有一个错误(issue 16671):如果您在声明中使用const enum(我为redux 操作类型这样做)并且您指定了transpileOnly 标志(create-react- app-typescript 包确实如此,这就是我知道的原因),枚举不会被内联!你可以跑进去,也可以不跑,但提前知道很有用!

【讨论】:

模块中的命名空间 export namespace 是 not a good idea 并添加 needless namespacing。关于export declare,看看André Pena 的回答。【参考方案4】:

要理解这一点,首先要理解“declare”关键字。

这是来自Gil Fink's Blog的一个很好的解释:

TypeScript 声明关键字用于声明可能不是源自 TypeScript 文件的变量。

例如,假设我们有一个名为 myLibrary 的库,它没有 TypeScript 声明文件,并且在全局命名空间中有一个名为 myLibrary 的命名空间。如果您想在 TypeScript 代码中使用该库,可以使用以下代码:

declare var myLibrary;

TypeScript 运行时将赋予 myLibrary 变量的类型是 any 类型。这里的问题是您在设计时不会为该变量提供 Intellisense,但您将能够在代码中使用该库。在不使用 declare 关键字的情况下具有相同行为的另一种选择是仅使用具有 any 类型的变量:

var myLibrary: any;

两个代码示例将产生相同的 JavaScript 输出,但 declare 示例更具可读性并且表达了环境声明。


所以在你理解了“declare”关键字之后,回到你找到的地方

export declare class Action
...

该类的真正实现可能在其他地方——可能是一个 .js 文件。

【讨论】:

“两个代码示例将产生相同的 JavaScript 输出”,这是不正确的:declare var myLibrary 将转译为空:typescriptlang.org/play/#code/… @Terrance Gil Flink 博客的链接对我不起作用(建立数据库连接时出错)。我认为这可能是相同的内容:dzone.com/articles/quick-tip-%E2%80%93-typescript-declare【参考方案5】:

找到了我要找的东西:

声明与 var

var 创建一个新变量。 declare 用于告诉 TypeScript 该变量已在别处创建。如果您使用declare,则不会向生成的 JavaScript 添加任何内容 - 它只是对编译器的提示。

例如,如果您使用定义 var externalModule 的外部脚本,您将使用 declare var externalModule 向 TypeScript 编译器提示 externalModule 已设置

【讨论】:

我有一个类似的场景,外部 JS 定义了一个变量 externalModule 等等。 externalModule 在运行时未定义但其他一些变量未定义的原因可能是什么?

以上是关于“export declare class Actions”中的“declare”有啥作用?的主要内容,如果未能解决你的问题,请参考以下文章