如何从节点模块导出 Typescript 接口?

Posted

技术标签:

【中文标题】如何从节点模块导出 Typescript 接口?【英文标题】:How do I export Typescript interfaces from a node module? 【发布时间】:2018-07-25 05:13:51 【问题描述】:

想通了!

最初,我试图像这样导入我的模块:

const qml = require('quill-marking-logic')
const  checkSentenceCombining, checkSentenceFragment, checkDiagnosticQuestion, checkFillInTheBlankQuestion, ConceptResult  = qml

因为我在尝试使用时遇到了TS2307: Cannot find module 'quill-marking-logic' 错误

import checkSentenceCombining, checkSentenceFragment, checkDiagnosticQuestion, checkFillInTheBlankQuestion, ConceptResult from 'quill-marking-logic'

这是因为我在导入应用程序的 tsconfig 中使用了"module": "es6",默认情况下将moduleResolution 选项设置为Classic。通过将其显式设置为node,我能够使用import 语法并获得我的接口!

原帖

我使用 Typescript 构建了一个节点模块,我将其用作另一个应用程序中的依赖项。我在模块中有几个接口,我试图从它的入口点导出,以便我可以在我的其他应用程序中使用它们,但它们在编译后被删除。我知道这是 Typescript 设计的一部分,因为接口用于运行时分析,但我想知道是否有办法绕过它,所以我不必在我的其他应用程序中再次定义它们并且必须维护两个地方的代码相同。我使用汇总作为我的捆绑器。

这是我的入口点的 .d.ts 版本的样子:

export  checkSentenceCombining  from './libs/graders/sentence_combining';
export  checkDiagnosticQuestion  from './libs/graders/diagnostic_question';
export  checkSentenceFragment  from './libs/graders/sentence_fragment';
export  checkFillInTheBlankQuestion  from './libs/graders/fill_in_the_blank';
export  Response, PartialResponse, ConceptResult, FocusPoint, IncorrectSequence, FeedbackObject, GradingObject, WordCountChange  from './interfaces/index';

最后一行是接口应该通过的地方。

这是我的 tsconfig:


    "compilerOptions": 
        "target": "es5",
        "module": "CommonJS",
        "moduleResolution": "node",
        "allowSyntheticDefaultImports": true,
        "sourceMap": false,
        "noImplicitAny": false,
        "lib": [
            "dom",
            "es7"
        ],
        "typeRoots": [
            "node_modules/@types/"
        ],
        "declaration": true
    

这是我尝试将其导入到的应用程序的 tsconfig:


    "compilerOptions": 
        "outDir": "./dist/",        // path to output directory
        "sourceMap": true,          // allow sourcemap support
        "strictNullChecks": true,   // enable strict null checks as a best practice
        "module": "es6",            // specifiy module code generation
        "jsx": "react",             // use typescript to transpile jsx to js
        "target": "es6",            // specify ECMAScript target version
        "allowJs": true,            // allow a partial TypeScript and javascript codebase
        "lib": ["ES2017", "DOM"],            //
        "allowSyntheticDefaultImports": true // Allow import React from 'react'
    

我指向 package.json 中“typings”键中生成的 .d.ts 文件。

【问题讨论】:

【参考方案1】:

您应该使用--declaration 选项为您的模块生成d.ts 文件。定义文件将包含导出的接口,您可以在应用程序中使用它们。

您应该在您的模块中包含定义文件,打字稿查找定义in:

类似地,非相对导入将遵循 Node.js 解析逻辑,首先查找文件,然后查找适用的文件夹。所以 import b from "moduleB" in source file /root/src/moduleA.ts 将导致以下查找:

/root/src/node_modules/moduleB.ts
/root/src/node_modules/moduleB.tsx
/root/src/node_modules/moduleB.d.ts
/root/src/node_modules/moduleB/package.json (if it specifies a "types" property)
/root/src/node_modules/moduleB/index.ts
/root/src/node_modules/moduleB/index.tsx
/root/src/node_modules/moduleB/index.d.ts 

【讨论】:

感谢提香!我在我的 tsconfig 中使用 --declaration 并在我的 package.json 中指定 .d.ts 文件,但接口似乎仍然没有通过。 @E.Friedberg 接口是从模块中导出的吗? 我已经编辑了原始帖子以显示我的入口点的样子。接口没有通过。【参考方案2】:

是的,这是可能的。为此,export 您希望在模块的入口点文件中提供给模块使用者的接口:

// in entry.ts
import  MyInterface1  from '/path/to/interface/one';
import  MyInterface2  from '/path/to/interface/two';

export  MyInterface1, MyInterface2 ;

然后,在使用此模块的代码中,您可以:

import  MyInterface1, MyInterface2  from 'my-module`;

为了使其工作,您需要确保在您的模块中将declaration 编译器选项设置为true - 这会导致编译器输出一个包含模块类型信息的.d.ts 文件.

最后一个难题是在模块的“package.json”中包含一个types 属性,该属性指向这个.d.ts 文件:


    "name": "my-module",
    "main": "./entry.js",
    "types": "./my-module.d.ts"

有关准备发布模块的更多信息: https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html

【讨论】:

嗨,内森,感谢您的帮助!我已经更新了我的原始帖子,以反映我拥有您在此处指示的所有代码,但有一个例外:package.json 的 'types' 和 'typings' 键之间是否有区别? @E.Friedberg:不,你可以使用任何一个——它们是同义词。【参考方案3】:

将此添加到您的 tsconfig.json 文件中:

"allowJs": false,
"declaration": true,

将此添加到您的 package.json 文件中:

"types": "dist/index.d.ts",

另外,不要忘记将您的 d.ts 文件放在您在 package.json 中发布的单独文件夹中,否则它们会丢失。例如,将它们放在src 文件夹旁边的typings 文件夹中,并将其添加到package.json

  "files": [
    "/dist",
    "/typings"
  ],

更多详情:https://medium.com/cameron-nokes/the-30-second-guide-to-publishing-a-typescript-package-to-npm-89d93ff7bccd

【讨论】:

以上是关于如何从节点模块导出 Typescript 接口?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 javascript/typescript 模块文件(导入/导出)访问 Vuex 商店?

Typescript 检查导出的接口

TypeScript - 条件模块导入/导出

如何让 TypeScript 对扩展从“节点模块”导入的类感到满意?

Vue / Typescript,得到模块'“*.vue”'没有导出成员

模块名称冲突时如何从 typescript.d.ts 文件访问接口?