如何扩展 TypeScript 模块而不覆盖它?

Gaj*_*jus 2 typescript

我想扩展fastify请求对象以包含有关会话的信息。

根据文档,这应该足够了:

declare module "fastify" {
  interface Session {
    user_id: string
    other_key: your_prefer_type
    id?: number
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我这样做,那么我所有的类型导入都会失败。

src/factories/createServer.ts:189:19 - error TS2349: This expression is not callable.
  Type 'typeof import("fastify")' has no call signatures.

189   const fastify = Fastify({
Run Code Online (Sandbox Code Playgroud)

如果我做这样的事情,

declare module "fastify" {
  import Fastify from 'fastify';

  interface Session {
    user_id: string
    other_key: your_prefer_type
    id?: number
  }

  export = Fastify;
}
Run Code Online (Sandbox Code Playgroud)

然后默认导入有效,但所有其他导入都会中断,例如

src/factories/createServer.ts:11:8 - error TS2305: Module '"fastify"' has no exported member 'FastifyRequest'.

11   type FastifyRequest,
Run Code Online (Sandbox Code Playgroud)

我在这里做错了什么?

ghy*_*ybs 9

非模块/全局脚本声明和经典模块之间存在一个不为人所知的区别:

\n
\n

JavaScript 规范声明任何没有export或 顶级的JavaScript 文件await都应被视为脚本而不是模块。

\n

在脚本文件内,变量和类型被声明为共享全局范围

\n
\n

在您的第一次尝试中很可能发生的情况是,您将声明放置在没有导入/导出语句的文件中。因此 TS 将其视为全局声明,覆盖了"fastify"模块的默认导出。

\n
// /src/globalDeclaration.d.ts\n// NO top-level import/export\n// Global declaration type\ndeclare module "fastify" {\n  interface Session {\n    user_id: string;\n    other_key: boolean; // your_prefer_type\n    id?: number;\n  }\n}\n\n// /src/index.ts\nimport Fastify from "fastify";\n\nconst fastify = Fastify(); // Error: Type \'typeof import("fastify")\' has no call signatures.ts(2349)\n
Run Code Online (Sandbox Code Playgroud)\n

CodeSandbox 上的演示:https://codesandbox.io/s/peaceful-resonance-fc1swm ?file=/src/index.ts

\n
\n

要解决该问题,请按照 TS 文档中的建议:

\n
\n

如果您的文件\xe2\x80\x99t 当前没有任何导入或导出,但您希望将其视为模块,请添加以下行:

\n

export {};

\n

这会将文件更改为不导出任何内容的模块。

\n
\n

因此,让我们添加空导出(可以在文件中的任何位置)以将声明仅转换为模块扩展。

\n

但是,请确保显式导入该文件,即使没有任何内容可以“导入”它:我们只是希望 TS 执行增强模块的副作用。

\n
// /src/moduleAugmentation.d.ts\nexport {}; // Make an import or export to turn the file into a module augmentation only\n\ndeclare module "fastify" {\n  interface Session {\n    user_id: string;\n    other_key: boolean; // your_prefer_type\n    id?: number;\n  }\n}\n\n// /src/index.ts\nimport Fastify, { FastifyRequest } from "fastify";\nimport fastifySession from "@fastify/session";\nimport fastifyCookie from "@fastify/cookie";\n\nimport "./moduleAugmentation"; // Now we have to explicitly import the module augmentation file, even just for its side effect\n\nconst fastify = Fastify();\nfastify.register(fastifyCookie);\nfastify.register(fastifySession, {\n  secret: "a secret with minimum length of 32 characters"\n});\n\nfastify.addHook("preHandler", (request, reply, next) => {\n  const b = request.session.other_key;\n  //                        ^? (property) Session.other_key: boolean\n  next();\n});\n
Run Code Online (Sandbox Code Playgroud)\n

CodeSandbox 上的演示:https://codesandbox.io/s/inspiring-phoebe-ly086x?file =/src/index.ts

\n