在TypeScript中创建一个全局变量

时间:2016-08-11 21:22:27

标签: typescript

在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而无需导入和创建对象。)

12 个答案:

答案 0 :(得分:36)

.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");

答案 1 :(得分:11)

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

logging.d.ts:

private function buildMenu($menu, $depth = 0, $nestingUL = true, $showElementOverride = false) {
    $ulNode = $this->doc->createElement('ul');

    if (!$depth) {
        $ulNode->setAttribute('id', 'primary-nav');
        $this->rootNode = $ulNode;
    }

    $this->appendtoNode($menu, $depth, $nestingUL, $ulNode, $showElementOverride);

    return $ulNode;
}

private function appendtoNode($menu, $depth, $nestingUL, $node, $showElementOverride = false) {
    foreach ($menu as $itemText => $item) {
        if (empty($item['hide']) || !($item['hide']) || $showElementOverride) {
            $node->appendChild($this->buildMenuItem($itemText, $item, $depth, $nestingUL));
        }

        else if ((array_key_exists('hide', $item) && $item['hide']) && !$nestingUL) {
            $tempMenu = $this->hiddenArraySkipNext($item);

            if (is_array($tempMenu)) $this->appendtoNode($tempMenu, $depth, $nestingUL, $node, $showElementOverride);
        }
    }
    return;
}

private function hiddenArraySkipNext($arr = array()) {
    $output = array();
    foreach ($arr as $tempArr) {
        $output = $tempArr;
        if (is_array($tempArr) && !empty($tempArr)) {
            foreach ($tempArr as $val) {
                if (is_array($val) && array_key_exists('hide', $val) && $val['hide']) {
                    $this->hiddenArraySkipNext($val);   
                }
            }
        }
    }
    return $output;
}

登录声明的 JS

declare var log: log4javascript.Logger;

initalize-app.ts

log = null;

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

注意:我认为这只有效,因为我将import './log-declaration.js'; // Call stuff to actually setup log. // Similar to this: log = functionToSetupLog(); TypeScript选项设置为true。

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

答案 2 :(得分:7)

好的,所以你做的事情可能更加丑陋,但无论如何......

但我这样做......

在纯TypeScript中可以做的是使用eval函数,如下所示:

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

以后你可以做

if (something === 'testing')

这只不过是在没有TypeScript拒绝编译的情况下强制执行指令的黑客攻击,而我们declare var用于TypeScript编译其余的代码。

答案 3 :(得分:4)

我只使用这个

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

答案 4 :(得分:1)

这是我解决的方法:

步骤:

  1. 声明了全局名称空间,例如custom.d.ts如下:

    声明全局{     命名空间NodeJS {         全局{             配置:{}         }     } } 导出默认全局;

  2. 将上面创建的文件映射到“ tsconfig.json”中,如下所示:

    “ typeRoots”:[“ src / types / custom.d.ts”]

  3. 在以下任何文件中获取上面创建的全局变量:

    console.log(global.config)

注意:

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

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

希望这会有所帮助!

谢谢

答案 5 :(得分:1)

this link是未来。

// Way 1
var abc: number
globalThis.abc = 200 // no error

// Way2
declare var age: number
globalThis.age = 18 // no error
  

注意:包含以上代码的文件不能包含任何import语句

到目前为止,这些是我想出的扩展全局对象的方法。

所有魔法都来自var。将var替换为letconst无效。

  

我尝试将模块globalThis扩展为globalThis,但失败了。

答案 6 :(得分:1)

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

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

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

2)创建具有以下内容的文件src/types/global.d.ts不导入!-这很重要),可以随时更改any以满足您的需要并使用{{1 }}界面,而不是window(如果您使用的是浏览器):

NodeJS

3)现在,您终于可以在需要的地方使用/实现/** * 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;

log

答案 7 :(得分:1)

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

我发现这可行:

import * as lodash from 'lodash';

(global as any)._ = lodash;

答案 8 :(得分:1)

使用更具体的示例(仅使用 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'.

您可能会注意到,我们declare对变量进行了处理,而以下同样有效。

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

答案 9 :(得分:0)

作为Dima V答案的补充,这就是我为此做的工作。

// First declare the window global outside the class

declare let window: any;

// Inside the required class method

let globVarName = window.globVarName;

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

我正在使用它:

interface Window {
    globalthing: any;
}

declare var globalthing: any;