【问题标题】:Create a global variable in TypeScript在 TypeScript 中创建一个全局变量
【发布时间】:2021-12-11 07:55:32
【问题描述】:

在 JavaScript 中我可以这样做:

 something = 'testing';

然后在另一个文件中:

 if (something === 'testing')

它会定义something(只要它们以正确的顺序调用)。

我似乎不知道如何在 TypeScript 中做到这一点。

这是我尝试过的。

在 .d.ts 文件中:

interface Window { something: string; }

然后在我的 main.ts 文件中:

 window.something = 'testing';

然后在另一个文件中:

 if (window.something  === 'testing')

这行得通。但我希望能够失去其中的window. 部分,而让我的something 成为全球性的。有没有办法在 TypeScript 中做到这一点?

(如果有人感兴趣,我真的想为我的应用程序设置日志记录。我希望能够从任何文件调用log.Debug,而无需导入和创建对象。)

【问题讨论】:

  • 另外:不要创建全局变量。使用 vscode 导入真的很容易。只需输入您要使用的内容,点击选项卡自动导入,然后继续。

标签: typescript


【解决方案1】:

如果我将 JavaScript 与 TypeScript 结合使用,我找到了一种可行的方法。

logging.d.ts:

declare var log: log4javascript.Logger;

日志声明。js

log = null;

初始化-app.ts

import './log-declaration.js';

// Call stuff to actually setup log.  
// Similar to this:
log = functionToSetupLog();

这会将它放在全局范围内,TypeScript 知道它。所以我可以在我的所有文件中使用它。

注意:我认为这只是因为我将 allowJs TypeScript 选项设置为 true。

如果有人发布纯 TypeScript 解决方案,我会接受。

【讨论】:

  • 在你的 initalize-app.ts 文件中你可以使用:declare var log: any; 然后你不需要有 d.ts 文件或 js 文件。您也可以将 any 替换为实际类型或接口定义。
【解决方案2】:

好吧,所以这可能比你所做的更难看,但无论如何......

但我也是这样做的……

您可以在纯 TypeScript 中执行此操作,就是像这样使用 eval 函数:

declare var something: string;
eval("something = 'testing';")

以后你就可以做到了

if (something === 'testing')

这只不过是在 TypeScript 拒绝编译的情况下强制执行指令的 hack,我们 declare var 让 TypeScript 编译其余代码。

【讨论】:

  • @DragonRock 我试过 Chrome 和 FF。所以我真的不确定发生了什么。无论如何,最终还是做了 declare var myglobalvar; (窗口).myglobalvar= {};然后我可以在没有窗口的情况下引用它。
  • 这确实应该使用.d.ts 定义文件来代替。
  • 这对我有用:export declare const SERVER = "10.1.1.26";
  • 非常不鼓励使用eval,这就是为什么我建议使用此解决方案stackoverflow.com/a/56984504/5506278
  • 使用eval 很脏,考虑改用Object.assign(globalThis, {something: 'something'})
【解决方案3】:

.d.ts 定义文件中

type MyGlobalFunctionType = (name: string) => void

如果您在浏览器中工作, 您将成员添加到浏览器的窗口上下文中:

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}

NodeJS 的想法相同:

declare module NodeJS {
  interface Global {
    myGlobalFunction: MyGlobalFunctionType
  }
}

现在您声明根变量(实际上将存在于窗口或全局中)

declare const myGlobalFunction: MyGlobalFunctionType;

然后在一个常规的 .ts 文件中,但作为副作用导入,你实际实现它:

global/* or window */.myGlobalFunction = function (name: string) {
  console.log("Hey !", name);
};

最后在代码库的其他地方使用它,其中之一是:

global/* or window */.myGlobalFunction("Kevin");

myGlobalFunction("Kevin");

【讨论】:

  • (顺便提个意见)说说创建一个简单全局变量的大量工作!大声笑
  • @Benoit 我没有得到“但作为副作用导入”的部分。你是什​​么意思?。我试过这样做,但它不适合我,你能分享一个源代码示例吗?
  • 这适用于.ts 文件,但是当我在我的.tsx 文件中使用window.myGlobalFunction 时,它就不行了。我还需要改变什么?!
  • d.ts 文件放在哪里,如何配置 TypeScript 来加载它?
  • 这太复杂了。
【解决方案4】:

我只用这个

import {globalVar} from "./globals";
declare let window:any;
window.globalVar = globalVar;

【讨论】:

  • 这会丢弃所有类型信息。也可以使用Javascript。
  • 当您完全在后端之外(出于不同目的)制作前端时,例如不同的团队或出于安全原因,此解决方案是有意义的。然后后端在窗口内注入一些东西。老实说,在这种情况下,我更喜欢在组件内指定每个变量。所以我相信这个解决方案可能会有生命:) 不要认为这是一个广泛的案例,但我有一天会遇到它......
【解决方案5】:

作为 Dima V 答案的一个插件,这是我为使这项工作为我所做的工作。

// First declare the window global outside the class

declare let window: any;

// Inside the required class method

let globVarName = window.globVarName;

【讨论】:

  • 投反对票的人能解释一下原因吗?
  • 嗯,这是一个解决方案,就像在仪表板上的“检查引擎”灯上贴一块黑色胶带。它解决了问题,但不是以正确的方式。它消除了类型。这不是最佳解决方案;这是一种解决方法,也适用于 typescript 的主要目的:拥有类型。
【解决方案6】:

这就是我修复它的方法:

步骤:

  1. 声明了一个全局命名空间,例如custom.d.ts 如下:
declare global {
    namespace NodeJS {
        interface Global {
            Config: {}
        }
    }
}
export default global;
  1. 将上面创建的文件映射到“tsconfig.json”如下:
"typeRoots": ["src/types/custom.d.ts" ]
  1. 在以下任意文件中获取上面创建的全局变量:
console.log(global.config)

注意:

  1. 打字稿版本:“3.0.1”。

  2. 在我的例子中,要求是在启动应用程序之前设置全局变量,并且该变量应该访问整个依赖对象,以便我们可以获得所需的配置属性。

希望这会有所帮助!

谢谢

【讨论】:

    【解决方案7】:

    globalThis 是未来。

    首先,TypeScript 文件有两种scopes

    全局范围

    如果您的文件没有任何importexport,则该文件将在全局范围 中执行,其中所有声明在此之外都是可见的文件。

    所以我们会像这样创建全局变量:

    // xx.d.ts
    declare var age: number
    
    // or 
    // xx.ts
    // with or without declare keyword
    var age: number
    
    // other.ts
    globalThis.age = 18 // no error
    

    所有魔法都来自var。将var 替换为letconst 将不起作用。

    模块范围

    如果您的文件有任何importexport,则该文件将在其自己的范围内执行,我们需要通过declaration-merging 将其全局扩展。

    // xx[.d].ts
    declare global {
      var age: number;
    }
    
    // other.ts
    globalThis.age = 18 // no error
    

    你可以在official docs看到更多关于模块的信息

    【讨论】:

    • 但是如果没有 'var' hack,你将如何做到这一点?我想这意味着,我将如何在 globalThis 上进行类型扩充?
    • @Tom var 是必要的。但是你可以在没有初始化的情况下声明变量
    • 为我工作(至少现在)非常感谢,我希望这个答案会上升。仅供参考:就我而言,我需要在 linter 的 globalThis 行上方添加 // @ts-ignore
    • 如何将年龄变量调用到任何打字稿文件中?
    • 即使这个解决方案可能有效,编译器仍然在抱怨:'元素隐式具有'任何'类型,因为类型'typeof globalThis'没有索引签名。',我不认为添加// @ts-ignore推荐是个好习惯
    【解决方案8】:

    我花了几个小时来找出正确的方法。就我而言,我正在尝试定义全局“日志”变量,因此步骤是:

    1) 配置您的 tsconfig.json 以包含您定义的类型(src/types 文件夹,node_modules - 由您决定):

    ...other stuff...
    "paths": {
      "*": ["node_modules/*", "src/types/*"]
    }
    

    2) 使用以下内容创建文件src/types/global.d.ts禁止导入! - 这很重要),随意更改any 以满足您的需求+ 使用window 接口而不是@ 987654329@ 如果您使用的是浏览器:

    /**
     * IMPORTANT - do not use imports in this file!
     * It will break global definition.
     */
    declare namespace NodeJS {
        export interface Global {
            log: any;
        }
    }
    
    declare var log: any;
    

    3) 现在您终于可以在需要的地方使用/实现log

    // in one file
    global.log = someCoolLogger();
    // in another file
    log.info('hello world');
    // or if its a variable
    global.log = 'INFO'
    

    【讨论】:

    • tsconfig.json 中的paths 是什么?文档没有提及它。
    • 为什么Global在定义中大写,而在实际使用中却没有?
    • @tambre 不确定为什么 TS 文档没有记录,您可以在此处找到有关此配置的一些详细信息:json.schemastore.org/tsconfig 和此处:basarat.gitbooks.io/typescript/docs/project/tsconfig.html 关于带有大写字母的 Global - 这是如何在 nodejs 命名空间中命名“全局”接口声明。
    【解决方案9】:

    我需要使 lodash 全局使用现有的 .js 文件,我无法更改,只需要。

    我发现这行得通:

    import * as lodash from 'lodash';
    
    (global as any)._ = lodash;
    

    【讨论】:

      【解决方案10】:

      这对我有用,如 this thread 中所述:

      declare let something: string;
      something = 'foo';
      

      【讨论】:

        【解决方案11】:

        我正在使用这个:

        interface Window {
            globalthing: any;
        }
        
        declare var globalthing: any;
        

        【讨论】:

          【解决方案12】:

          使用更具体的示例(仅 TypeScript 不与 JavaScript 混合)扩展关于 globalThis(参见 MDNTypeScript 3.4 note)的其他答案,因为该行为相当令人困惑。所有示例都在 Nodejs v12.14.1 和 TypeScript Version 4.2.3 下运行。

          具有全局范围的最简单情况

          declare var ENVIRONMENT: string;
          globalThis.ENVIRONMENT = 'PROD';
          console.log(ENVIRONMENT);
          console.log(globalThis.ENVIRONMENT);
          // output
          // PROD
          // PROD
          

          此文件不是importexport,因此它是一个全局范围文件。您可以编译上述 TypeScript 代码而不会出现任何错误。请注意,您必须使用var。使用let 会抛出error TS2339: Property 'ENVIRONMENT' does not exist on type 'typeof globalThis'.

          您可能会注意到我们declared 变量,而不是下面的变量。

          var ENVIRONMENT: string;
          ENVIRONMENT = 'DEV';
          globalThis.ENVIRONMENT = 'PROD';
          console.log(ENVIRONMENT);
          console.log(globalThis.ENVIRONMENT);
          // output
          // DEV
          // PROD
          

          输出来自 Nodejs v12.14.1。我还在 Chrome 中对其进行了测试(编译为 JS 之后)并输出PROD。所以我建议一直使用globalThis

          具有模块范围的简单案例

          declare var ENVIRONMENT: string;
          globalThis.ENVIRONMENT = 'PROD';
          export {};
          

          一旦我们添加export语句,它就变成了一个模块范围文件,它抛出error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.解决方案是augment global scope

          declare global {
            var ENVIRONMENT: string;
          }
          globalThis.ENVIRONMENT = 'PROD';
          console.log(globalThis.ENVIRONMENT);
          export {};
          

          你仍然必须使用var,否则你会得到error TS2339: Property 'ENVIRONMENT' does not exist on type 'typeof globalThis'.

          导入副作用

          // ./main.ts
          import './environment_prod';
          
          console.log(ENVIRONMENT);
          console.log(globalThis.ENVIRONMENT);
          
          // ./environment_prod.ts
          declare var ENVIRONMENT: string;
          globalThis.ENVIRONMENT = 'PROD';
          

          或者

          // ./environment_prod.ts
          declare global {
            var ENVIRONMENT: string;
          }
          globalThis.ENVIRONMENT = 'PROD';
          export {}; // Makes the current file a module.
          

          浏览两个文件

          假设main.tsenvironment_prod.ts 都是入口文件。 Browserify 会将它们(在编译为 JS 之后)包装到需要使用 globalThis 的本地作用域函数中。

          // ./main.ts
          declare var ENVIRONMENT: string;
          console.log(ENVIRONMENT);
          console.log(globalThis.ENVIRONMENT);
          
          // ./environment_prod.ts
          declare var ENVIRONMENT: string;
          globalThis.ENVIRONMENT = 'PROD';
          

          但是共享一个声明文件更安全,然后可以由两个入口文件导入,以避免变量名或类型名的拼写错误。

          // ./main.ts
          import './environment';
          
          console.log(ENVIRONMENT);
          console.log(globalThis.ENVIRONMENT);
          
          // ./environment_prod.ts
          import './environment';
          
          globalThis.ENVIRONMENT = 'PROD';
          
          // ./environment.ts
          type Environment = 'PROD' | 'DEV' | 'LOCAL';
          
          declare var ENVIRONMENT: Environment;
          

          注意顺序很重要:browserify environment_prod.js main.js > bin.js

          【讨论】:

            【解决方案13】:

            此处发布的文字是文章TypeScript and Global Variables in Node.js的简短版本

            自从 TypeScript 3.4 发布以来,就有了一种记录方法。

            在项目的根目录中创建一个名为global.d.ts 的文件,内容如下。请注意:

            • var 的使用,这是它工作所必需的(有关这方面的信息,请参阅 typescriptlang.org)。
            • 没有export {},所有变量都会变成any
            declare global {
                var Config: {
                    Foo: string;
                };
                var Foo: string;
            }
            export { };
            

            确保 tsconfig.json 包含适合 includeexclude 的部分。示例如下:

            "include": [
                "src/**/*.ts",
              ],
              "exclude": [
                "node_modules",
                "<node_internals>/**",
                "bin/**"
              ]
            

            要使用变量,只需执行以下操作:

            import * as Logger from './logger';
            
            // Initialize early
            global.log = Logger;
            
            // Use it
            log.Info("Booting system...");
            

            享受:)

            【讨论】:

            • 最后.. export { }; 是关键。在.ts 中,您可以交替使用global.logglobalThis.log
            【解决方案14】:

            它在浏览器上工作
            我在https://stackoverflow.com/a/12709880/15859431找到了这个

            declare global {
                interface Window {
                    myGlobalFunction: myGlobalFunction
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2020-09-24
              • 2021-03-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-07-27
              相关资源
              最近更新 更多