如何制作具有全局可访问类型的 NPM 模块

m93*_*93a 5 npm typescript

关键字:使用 TypeScript 模块中的类型而不导入,发布仅包含类型的包,告诉 TypeScript 在 NPM 模块中查找类型。


我想发布一个包含全局可访问类型的 NPM 模块,很像lib.d.ts.

模块应该有什么结构,我如何将它包含在另一个项目中?

如果使类型全局可见太难了,那么要求它就<reference/>足够了,但是当我尝试时这不起作用。


在我想使用这些类型的项目中,我有一个src包含所有源代码的bin文件夹和包含tsc.

包含类型的模块几乎可以具有任何结构,只要它有效,我真的不在乎。


到目前为止,我已经尝试了很多很多组合,包括export输入类型、declare输入类型、export declare输入类型、将它们放入.ts或放入.d.ts文件、在包内的文件夹中移动它们node_modulesimport输入它们、<reference/>输入它们、将它们放入rootDirs……但什么都没有工作。缺乏这方面的良好文档也无济于事。

Jam*_*rch 7

我必须为我的日志库解决这个问题,winston-jsonl-logger. 它使用一个名为 的全局变量来扩充全局范围logger。我同意这是 TypeScript 中最难(如果不是最难)的问题之一,尤其是因为缺乏足够的文档。在这个例子中,我创建了一个使用全局可见('script')和模块可见('module')类型的库。澄清官方术语

在 TypeScript 中,就像在 ECMAScript 2015 中一样,任何包含顶级importexport模块的文件都被视为模块。相反,没有任何顶级importexport声明的文件被视为脚本,其内容在全局范围内可用(因此也对模块可用)。

目录结构

我的src文件夹被转换为dist. test被转译忽略。

您的类型必须命名index.d.ts并嵌套在名称与您的项目相同的文件夹中(严格来说可能是 中指定的名称package.json)。这就是结构typeRoots将要寻找的。

.
??? README.md
??? dist
?   ??? Logger.d.ts
?   ??? Logger.js
?   ??? Logger.js.map
?   ??? initLoggers.d.ts
?   ??? initLoggers.js
?   ??? initLoggers.js.map
??? package-lock.json
??? package.json
??? src
?   ??? Logger.ts
?   ??? initLoggers.ts
??? test
?   ??? index.ts
??? tsconfig.json
??? typings
    ??? winston-jsonl-logger
        ??? index.d.ts
Run Code Online (Sandbox Code Playgroud)

“脚本”打字

脚本类型是那些缺少顶级importexport. 它们将在使用它们的项目中全局可见。

当然,由于它们不能使用顶级import声明,因此它们的描述性受到限制;你可能经常any在这里看到很多使用。这是我试图在我自己的问题中解决的问题

.
??? README.md
??? dist
?   ??? Logger.d.ts
?   ??? Logger.js
?   ??? Logger.js.map
?   ??? initLoggers.d.ts
?   ??? initLoggers.js
?   ??? initLoggers.js.map
??? package-lock.json
??? package.json
??? src
?   ??? Logger.ts
?   ??? initLoggers.ts
??? test
?   ??? index.ts
??? tsconfig.json
??? typings
    ??? winston-jsonl-logger
        ??? index.d.ts
Run Code Online (Sandbox Code Playgroud)

如果您logger在全局范围内使用,它将像any现在一样输入。

“模块”类型

模块类型可以使用顶级importor export,但只有在模块被导入到项目中时才会看到它们。即它们在整个项目中是不可见的。

// typings/index.d.ts
declare namespace NodeJS {
    export interface Global {
        logger?: any;
        log?: any;
        logInfo?: any;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你logger在全局范围内使用,它仍然会被输入为any,但至少global.logger会有正确的类型。

为了保证这些类型在您的项目中可见,请my-project确保my-projectwinston-jsonl-logger; 我在我的应用程序的入口点执行此操作。

package.json

我没有使用typingsortypes字段(也许指定"typings": "typings/winston-jsonl-logger/index.d.ts"意味着包不必明确声明我的类型的路径;我不知道),但我确实确保分发我的类型文件夹。

{
  "name": "winston-jsonl-logger",
  "version": "0.5.3",
  "description": "TypeScript JSONL logger.",
  "main": "dist/Logger.js",
  "files": [
    "dist",
    "typings"
  ],
  "devDependencies": {
    "@types/logform": "1.2.0",
    "@types/node": ">=9.6.21",
    "ts-node": "7.0.1",
    "typescript": "3.1.1"
  },
  "dependencies": {
    "winston": "3.2.0",
    "winston-daily-rotate-file": "3.6.0",
    "winston-elasticsearch": "0.7.4"
  }
}
Run Code Online (Sandbox Code Playgroud)

省略字段:repository, keywords, author, license, homepage, publishConfig, and scripts; 否则,这就是一切。

tsconfig.json

对于 lib 本身

没什么特别的。只是您的标准tsc --init默认值。

对于使用 lib 的项目

只要确保你添加一个typeRoots看起来像这样的:

{
  "compilerOptions": {
    // ...All your current fields, but also:
    "typeRoots": [
      "node_modules/@types",
      "node_modules/winston-jsonl-logger/typings/winston-jsonl-logger"
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您正在使用 ts-node

这里还有更多问题。默认情况下,ts-node忽略脚本类型,只导入入门级导入的后代(这样做的原因是速度/效率)。你可以迫使它来解决进口就像tsc确实通过设置环境变量:TS_NODE_FILES=true。是的,它运行测试的速度会变慢,但另一方面,它完全可以工作。

如果您ts-node通过命令行使用,请将TS_NODE_FILES环境变量声明为true. 我还必须声明TS_NODE_CACHEfalse,因为在ts-node解决导入/依赖项时(版本 7.0.1 – 可能仍然是一个问题)中的一个莫名其妙的缓存错误。

// initLoggers.ts
import {Logger} from "./Logger";
import {LogEntry, Logger as WinstonLogger} from "winston";

// Now we can be more descriptive about the global typings
declare global {
    const logger: Logger;
    // LogEntry's interface: { level: string, message: string, data?: any }
    function log(entry: LogEntry): WinstonLogger;
    function logInfo(message: string, data?: any): WinstonLogger;
}

export function initLoggers(){
    global.logger = new Logger();
    global.log = logger.log.bind(logger);
    global.logInfo = (message: string, data?: any) => {
        return logger.log({ level: "info", message, data });
    }
}
Run Code Online (Sandbox Code Playgroud)

我通常使用,ts-node因为我正在用 Mocha 进行测试。下面是我如何ts-node从 Mocha传递环境变量:

{
  "name": "winston-jsonl-logger",
  "version": "0.5.3",
  "description": "TypeScript JSONL logger.",
  "main": "dist/Logger.js",
  "files": [
    "dist",
    "typings"
  ],
  "devDependencies": {
    "@types/logform": "1.2.0",
    "@types/node": ">=9.6.21",
    "ts-node": "7.0.1",
    "typescript": "3.1.1"
  },
  "dependencies": {
    "winston": "3.2.0",
    "winston-daily-rotate-file": "3.6.0",
    "winston-elasticsearch": "0.7.4"
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

  • 从 [`tsconfig.json` 文档](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) 中:“*types 包*是一个文件夹,其中包含一个名为“index.d”的文件。 ts` 或包含 `package.json` 且包含 `types` 字段的文件夹...例如,如果您使用 `import "foo"` 语句,TypeScript 仍可能会查找 `node_modules` 和 `node_modules/@ types` 文件夹来查找 `foo` 包。” 它们在这里可能更明确一些,但它们的约定是将类型包表示为“&lt;package name&gt;/index.d.ts”。[此处](https://github.com/Microsoft/TypeScript/issues/11137#issuecomment-251755605)。 (2认同)