如何从一个Node.js模块中导出Typescript接口?

16

搞定了!

最开始,我尝试像这样导入我的模块:

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构建了一个Node模块,并将其用作另一个应用程序的依赖项。该模块中有一些接口,我正在尝试从其入口点导出这些接口,以便我可以在其他应用程序中使用它们,但它们在编译后被擦除。我知道这是TypeScript设计的一部分,因为接口用于运行时分析,但我想知道是否有办法绕过它,以便我不必在其他应用程序中再次定义它们并且需要在两个位置维护相同的代码。 我正在使用rollup作为我的打包工具。
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 文件。

3个回答

10

是的,这是可能的。要做到这一点,在模块的入口文件中export您想要对模块的消费者提供的接口:

是的,这是可能的。要做到这一点,在模块的入口文件中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" 中包含一个指向该 .d.ts 文件的 types 属性。
{
    "name": "my-module",
    "main": "./entry.js",
    "types": "./my-module.d.ts"
}

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


嘿,Nathan,感谢你的帮助!我已经更新了我的原始帖子,以反映我拥有你在这里指示的所有代码,只有一个例外:package.json中的“types”和“typings”键之间是否有区别? - E. Friedberg
@E.Friedberg:不,你可以使用任何一个词 - 它们是同义词。 - Nathan Friend

1
你应该使用--declaration选项来生成你的模块的d.ts文件。定义文件将包含导出的接口,你可以在应用程序中使用它们。
你应该将定义文件与你的模块一起包含在typescript查找定义位置的地方。

Similarly a non-relative import will follow the Node.js resolution logic, first looking up a file, then looking up an applicable folder. So import { b } from "moduleB" in source file /root/src/moduleA.ts would result in the following lookups:

/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 

谢谢Titian!我在tsconfig中使用了--declaration,并在package.json中指定了.d.ts文件,但接口似乎仍然没有传递过来。 - E. Friedberg
@E.Friedberg 这个模块中的接口被导出了吗? - Titian Cernicova-Dragomir
我已经编辑了原始帖子,以展示我的入口点是什么样子的。接口没有出现。 - E. Friedberg

1
将以下内容添加到您的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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接