在node.js中扩展TypeScript Global对象

d51*_*512 46 global node.js typescript

我有一个node.js应用程序,它将一些配置信息附加到global对象:

global.myConfig = {
    a: 1,
    b: 2
}
Run Code Online (Sandbox Code Playgroud)

TypeScript编译器不喜欢这个,因为该Global类型没有名为的对象myConfig:

TS2339:"全局"类型中不存在属性"myConfig".

我不想这样做:

global['myConfig'] = { ... }
Run Code Online (Sandbox Code Playgroud)

如何扩展Global类型以包含myConfig或仅告诉TypeScript闭嘴并信任我?我更喜欢第一个.

我不想改变里面的声明node.d.ts.我看到了这个SO帖子并尝试了这个:

declare module NodeJS  {
    interface Global {
        myConfig: any
    }
}
Run Code Online (Sandbox Code Playgroud)

作为扩展现有Global界面的一种方式,但它似乎没有任何影响.

bas*_*rat 56

我看到了这个SO帖子并尝试了这个:

你可能有类似的东西vendor.d.ts:

// some import 
// AND/OR some export

declare module NodeJS  {
    interface Global {
        spotConfig: any
    }
}
Run Code Online (Sandbox Code Playgroud)

您的文件需要清除任何根级别importexports.这会将文件转换为模块并将其与全局类型声明命名空间断开连接.

更多:https://basarat.gitbooks.io/typescript/content/docs/project/modules.html

  • @basarat - RE:"您的文件需要清除任何根级别的导入或导出",根据https://www.typescriptlang.org/docs/handbook/,无法在此处应用"全局修改模块" declaration-files/templates/global-modification-module-d-ts.html?如果我正确地理解了这个例子,那么在`declare global {namespace NodeJS {...}}`中添加一些内容应该允许你同时拥有全局命名空间扩充和模块导出. (3认同)
  • `NodeJS`被声明为命名空间,而不是模块 (2认同)

Nik*_*iko 34

为了避免Typescript声称这样的事情:

TS2339:"全局"类型中不存在属性"myConfig".

我建议定义自定义类型.我src/types/custom.d.ts在我的项目中的文件下做:

declare global {
  namespace NodeJS {
    interface Global {
        myConfig: {
          a: number;
          b: number;
        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我确保tsconfig.json文件中的Typescript考虑这些:

{
  ...
  "files": [
    ...
    "src/types/custom.d.ts"
  ]
}
Run Code Online (Sandbox Code Playgroud)

现在您可以安全地使用自定义属性:

console.log(global.myConfig.a);
Run Code Online (Sandbox Code Playgroud)

  • 这是更好的答案.正如扩展`Window`客户端应该使用`declare global`. (4认同)
  • `declare global` 似乎是无效的语法 (3认同)
  • 我收到错误“声明修饰符不能在已有的环境上下文中使用”。 (2认同)

Sha*_*tin 14

将以下文件放入项目的根目录中.

global.d.ts

declare namespace NodeJS {
  export interface Global {
    myConfig: any
  }
}
Run Code Online (Sandbox Code Playgroud)

我们正在使用"@types/node": "^7.0.18"和TypeScript Version 2.3.4.我们的tsconfig.json文件如下所示:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6"  
    },
    "exclude": [
        "node_modules"
    ]
}
Run Code Online (Sandbox Code Playgroud)

  • 我收到错误:“TS2339:属性‘myConfig’在类型‘Global’上不存在。”。 (2认同)

ale*_*xor 11

由于node@16NodeJS.Global界面已被移除以支持globalThis.

您可以在模块文件中将新的全局变量声明为:

declare global {
  var NEW_GLOBAL: string;
}
Run Code Online (Sandbox Code Playgroud)

在非模块文件(没有顶级导入/导出)中:

declare var NEW_GLOBAL: string;
Run Code Online (Sandbox Code Playgroud)

重要提示:变量必须声明为var. letconst变量未显示在globalThis.

  • 这是截至 2021 年 9 月有效的唯一答案!(节点 v14 LTS) (10认同)
  • 这是关于 TS 声明上下文中的 var 的一个非常好的观点。 (3认同)
  • 不适合我,编译器仍然抱怨以下消息:“元素隐式具有“任何”类型,因为类型“typeof globalThis”没有索引签名”。 (2认同)
  • 以及如何使用在 Server.ts 中声明和设置的 NEW_GLOBAL,例如:用户控制器?我需要以某种方式导入它吗?Typescript 如何知道它已经在 Servert.s 中声明了? (2认同)

Blu*_*dis 10

使用“命名空间”而不是“模块”来声明自定义 TypeScript

如果您使用上述任何答案,并且使用的是较新版本的 Typescript,您将收到关于使用"module"的唠叨。您应该考虑命名空间。

为了满足这里的要求,您实际上需要的不仅仅是扩展 Global 接口。如果您希望它可以直接从“globalThis”上下文访问,您还需要使用该类型创建一个常量。

注意:虽然 OP 询问对象文字,但过程与您在下面看到的相同。而不是“调试”类型是一个函数,您只需根据需要定义接口,然后将“调试:”更改为 myConfig 或您希望的任何内容。

// typically I'll store the below in something like "typings.d.ts"
// this is because, at least typically, these overrides tend to
// be minimal in nature. You could break them up and Typescript
// will pick them up if you wish.

// Augmentations for the global scope can only be directly nested 
// in external modules or ambient module declarations.
export {}

declare global {
  // Definition or type for the function.
  type Debug = (label: string) => (message: any, ...args: any[]) => void

  // If defining an object you might do something like this
  // interface IConfig { a: number, b: number }

  // Extend the Global interface for the NodeJS namespace.
  namespace NodeJS {
    interface Global {
      // Reference our above type, 
      // this allows global.debug to be used anywhere in our code.
      debug: Debug
    }
  }
  
  // This allows us to simply call debug('some_label')('some debug message')
  // from anywhere in our code.
  const debug: Debug
}
Run Code Online (Sandbox Code Playgroud)

如何使用上述内容

在这个例子中,为了完整起见,我们所做的只是定义了一个全局变量,这样我们就可以记录一条简单的调试消息。下面是我们如何将方法绑定到我们的全局上下文。

global.debug = (label: string) => (message: any, ...args: any[]) => console.log(message, ...args)
Run Code Online (Sandbox Code Playgroud)

我们也可以直接调用我们的全局调试方法:

debug('express')(`${req.method}: ${req.url}`)
Run Code Online (Sandbox Code Playgroud)


Ale*_*lls 6

唯一对我有用的是:

// lib/my.d.ts

import Global = NodeJS.Global;
export interface CDTGlobal extends Global {
  cdtProjectRoot: string
}
Run Code Online (Sandbox Code Playgroud)

然后在其他文件中使用它

import {CDTGlobal} from "../lib/my.d.ts";
declare const global: CDTGlobal;

const cwd = global.cdtProjectRoot; // works
Run Code Online (Sandbox Code Playgroud)


Ben*_*uer 5

对我有用的是:

declare global {
  module NodeJS {
    interface Global {
      myConfig: any;
    }
  }
}

global.myConfig = 'it works!';
Run Code Online (Sandbox Code Playgroud)

唯一的缺点是在使用它时你必须关闭 ESLint 规则@typescript-eslint/no-namespace

为了完整起见,这里是我的tsconfig.json

{
  "compilerOptions": {
    "declaration": true,
    "emitDecoratorMetadata": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "react",
    "lib": ["dom", "es2017"],
    "module": "commonjs",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "outDir": "dist",
    "removeComments": true,
    "resolveJsonModule": true,
    "rootDir": "src",
    "sourceMap": true,
    "strict": true,
    "target": "es6"
  },
  "exclude": ["dist", "node_modules"]
}
Run Code Online (Sandbox Code Playgroud)