【问题标题】:What is the simplest possible example of where `declare` keyword is useful in TypeScript?`declare` 关键字在 TypeScript 中有用的最简单示例是什么?
【发布时间】:2019-09-16 01:49:12
【问题描述】:

我已经阅读了文档(即this)和一些关于 TypeScript 中的 declare 关键字的博客文章,但我仍然不明白。我想要的是一个最简单用法的清晰示例。

这是我最初提出这个最简单示例的推理路线(可能不正确):

有一个.js 文件导出一些东西(无类型,因为这是纯 JS)。

无论导出的.js 文件如何,都有一个.ts 文件导入。

需要导出和导入什么(对象?函数?)我才能看到 TS 显示可以通过使用 declare 修复的错误?

【问题讨论】:

标签: typescript


【解决方案1】:

你的例子是正确的。例如,您正在使用一个用纯 javascript 编写的节点模块(没有可用的类型),因此 tscompiler 会注意到这一点(因为它搜索通常在节点模块中的类型或额外的@typings/package)。

但是,您可以自己提供这些类型,方法是告诉 tsconfig.json 中的 tscompiler 查看文件 xyz.d.ts 中的类型,例如

tsconfig.json
{
  "files": [
    "typings/index.d.ts"
  ]
}

index.d.ts 是收集所有自定义类型的地方,看起来像这样

index.d.ts
/// <reference path="custom-typings.d.ts" />

并且custom-typings.d.ts 中有实际的类型。这就是declare 关键字发挥作用的地方

custom-typings.d.ts
declare module "the-untyped-node-module-name" {
    export default class TheNodeModuleClass { 
        static showNotification(string: any): void;
    }
}

现在 Typescript 编译器知道在 the-untyped-node-module-name 中有一个 TheNodeModuleClass,它具有静态函数 showNotification

欲了解更多信息See Typscript Modules


这是关键字declare 的一个用例。当然还有更多,比如declare vardeclare functiondeclare class等等。

【讨论】:

  • 这里有一个简单的要点:gist.github.com/evian-pring/ce3aa59c01f6fb2b1cec806519fc8f89 我可以假设myModule.js 相当于一个用普通 JS 编写的节点模块,我会通过 node_modules 添加到我的项目中吗?如果 TypeScript 可以推断出这样的类型,你能举一个它不能推断的例子吗?我必须使用declare
  • @evianpring 那个叫做Contextual Typing 并以这种方式工作。但是它不适用于来自 node_modules 的外部导入。
【解决方案2】:

上面的 Murat Karagöz 回答指出了正确的方向,这个回答将提供实际代码以及我们将使用 declare 的最小示例。

Here 是一个非常简单的 npm 模块:只有一个 index.js 文件,它使用一种方法导出一个对象。这里没有类型声明,因为它只是 JS。

const item = {
    price: 5,
    name: 'item1',
};

export const MyModuleObject = { method: () => item };

Here 是一个非常简单的 TypeScript npm 项目,有一个依赖项:上面链接的 JS 项目。因此后者是一个没有类型的导入 npm 模块。这里是TS项目中的index.ts文件:

/// <reference path="index.d.ts"/>

import { MyModuleObject } from 'npmModule';

import { LocalModuleObject } from './module';

// Without the "reference path" line, TS complains in line 3 that it could not find a declaration file for 'npmModule'.
// In this case, the import has type any, so TS does not complain about the call below to an inexistent method.
// When we uncomment line 1, we get a TS error on line 8: property 'test' does not exist on type { method: ... }
MyModuleObject.test();


// TS complains that test does not exist on type { method: ... }
// Here we did not need to have a `declare` statement in a type definitions file for TS to know this because here TS is
// using contextual typing:
LocalModuleObject.test();

下面是index.d.ts的代码:

declare module "npmModule" {
    export const Item: {
        price: number,
        name: string
    }

    export const MyModuleObject: {
        method: () => Item
    }
}

还有./module的代码:

export const LocalModuleObject = { method: () => 10 };

这是为什么使用声明的示例 - 我把它放在index.ts 的cmets 中,但让我用更多的话来解释它。 index.ts 正在从外部模块(node_modules 中的一个)导入一个对象,并从本地模块 (./module.js) 导入另一个对象。两个模块都使用一种名为method 的方法导出对象。在index.ts 中,我在每个对象上调用了一个不存在的方法test

TS 在本地模块的导入上使用上下文类型,因此它知道test 不存在于对象上。在外部模块中导入对象时不会发生这种情况:此导入是使用类型 any 导入的。因此,TS 不会抱怨调用不存在的方法test。但是,它确实抱怨没有为外部模块输入类型,所以这是暗示正在使用隐式 any

我们可以通过定义一个为外部库提供类型的index.d.ts 来解决后一种问题。这是使用declare module 的地方:它声明了模块npmModule 导出的内容; npmModule 是外部导入。在 index.ts 中,我们必须添加行 /// &lt;reference path="index.d.ts"/&gt; 以便 TS 知道在哪里查找类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-12
    • 2020-10-11
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多