编写 .d.ts 文件以便我可以与 JavaScript 和 TypeScript 共享常量?

Posted

技术标签:

【中文标题】编写 .d.ts 文件以便我可以与 JavaScript 和 TypeScript 共享常量?【英文标题】:Writing .d.ts file so I can share constants with JavaScript and TypeScript? 【发布时间】:2018-06-26 14:46:15 【问题描述】:

我正在开发一个 node.js 项目,由于历史原因,该项目同时涉及 TypeScript 和 javascript。我想设置一些可以在两种语言中使用的项目范围的常量。显而易见:编写一个带有常量的.js 文件,以及一个包含TypeScript 使用类型的.d.ts 文件。但是没有:解决这个问题(和 RTFMing)的几个小时让我无处可去。

这是我对常量文件的第一次尝试:

// constants.js
const MY_CONST_1 = 1;
exports.MY_CONST_1 = MY_CONST_1;

... 以及使用它的 JavaScript:

// consumer.js
let constants = require('./constants');
let one = constants.MY_CONST_1;

效果很好,但是当我在 TypeScript 中尝试显而易见的时候:

// consumer.ts
import * as constants from './constants';
let one: number = constants.MY_CONST_1;

不:error TS2307: Cannot find module './constants'. 所以,必须在与constants.js 文件相同的目录中编写一个constants.d.ts 文件,对吧?听起来很容易,但六种不同的尝试已经产生了准确的结果。不管我做什么,Typescript 都会抱怨error TS2306: File '/Users/griscom/Documents/Work/test/constants.d.ts' is not a module

那么,一个成功的constants.d.ts 文件应该是什么样的?或者,如果我必须在 constants.js 中进行更改才能使这一切正常工作,它们会是什么?

附:这是我的tsconfig.json 文件:


  "compilerOptions": 
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "noImplicitReturns": true
  

(这似乎是一个简单而明显的需求;令人沮丧的是这个过程是多么不透明。)

【问题讨论】:

【参考方案1】:

选项 1:allowJs

尝试使用编译器选项allowJs: true。这将允许您从 ./constants 进行原始导入,即使它是 .js 文件,也无需创建单独的 .d.ts 文件。 TypeScript 将理解来自 .js 文件的可推断类型,例如,您将针对 MY_CONST_1 作为数字进行类型检查。

正如您在评论中所说,这需要将源文件与输出文件分开,因为它不能在与 JS 源文件相同的位置输出 JS 文件。

选项2:constants.d.ts声明文件

鉴于您的源文件如下所示:

// constants.js
export const MY_CONST_1 = 1;

您可以编写一个如下所示的constants.d.ts 文件:

// constants.d.ts
export const MY_CONST_1: number;

您之前的尝试中没有使用声明module,它用于声明外部模块的类型(例如来自node_modules)。在这种情况下,只需将constants.d.ts 文件与constants.js 放在同一目录中并使用export 将告诉TS 它是一个导出该值的JS 模块:

import  MY_CONST_1  from "./constants";
import * as constants from "./constants";

需要牢记的重要一点.d.ts 文件不会与.js 文件进行核对以确保它实际上是正确的,这取决于您。因此,如果您对.js 文件进行更改,您必须确保相应地正确更新.d.ts 文件。编译错误或缺少编译错误并不意味着它是正确的或不正确的。这是allowJs 存在的原因之一,因为它避免了此类泄漏。

【讨论】:

好主意,但是我项目中的所有其他 JavaScript 文件都会触发错误:“无法写入文件 XXXX,因为它会覆盖输入文件”。 是的,您需要将源文件与输出文件分开。 JS 源文件将以最小的转换被复制(例如,仅 ES6 到 ES5 语法)。 为什么不呢?或者写一个.d.ts 文件应该可以,你试过什么? 这是一个大型的现有项目,添加此功能的好处将被更改构建过程的复杂性所抵消。关于.d.ts 文件,我尝试了一些我在网上找到的示例,但编译器一直在抱怨。 我知道这种感觉,但根据我的经验,这通常更像是一种心理障碍。 :) 您可以发布您在问题中尝试过的.d.ts 内容吗?【参考方案2】:
export const MyConst =1;

或者

export class MyGroup 
    static MyConst: number

通常不要使用模块,因为这与 inports 中模块的含义不兼容。而是使用与具有静态成员的类非常相似的“命名空间”。这意味着您可能会这样做(在手机上但无法尝试):

export namespace MyNamespace 
    export const MyConst = 1;

但最后尽量避免将东西包装在额外的命名空间和类等中,因为导入语法是模块。它还使您的代码可摇晃。

【讨论】:

michelenasti.com/2019/01/23/…【参考方案3】:

另一种选择:使用import for side effects only。实际上,您的常量是全局的,即由于缺少 export 关键字而未在模块中定义:

import './constants';

与另一个回复中提到的allowJs 编译器选项结合使用。

【讨论】:

以上是关于编写 .d.ts 文件以便我可以与 JavaScript 和 TypeScript 共享常量?的主要内容,如果未能解决你的问题,请参考以下文章

如何从流代码生成 .d.ts 类型?

您如何为包含多个模块/类的“复杂”香草 JavaScript 库编写工作 .d.ts 文件?

如何使用从多个 ts 文件生成的单个 .d.ts 文件

打字稿中的 *.d.ts 与 *.ts 有啥区别?

获取TypeScript的声明文件.d.ts

打字稿:如何为图像自动生成 d.ts 文件