Typescript: Allow module definitions to be declared as global variables

Created on 15 May 2015  ·  11Comments  ·  Source: microsoft/TypeScript

I have the React type definition file (that is declared using an external module). In my source files, I usually do:

import * as R from "react"

and can then happily use R.createElement(... etc in a strongly typed fashion. I can even do:

let _r = R;
_r.createElement(...

What I want is to not have to import R in every file, and instead have it as a global declaration (yes, I'm willing to polute the global namespace with a few variables). I've tried, in a .d.ts:

import * as React from "react";
declare var R : React;

This doesn't work though, I get "Cannot find name 'React'". Is there another way to export the entire module as global, without having modify the underling react.d.ts?

Question

Most helpful comment

Hi @Evertt indeed I'm getting this error now too. Initially my source code wasn't using ES6 module syntax but once I refactored some files to that syntax I got the same error. Did some research and what worked for me now is when I create second file globals.d.ts and put it also into the typings folder:

import * as _R from 'ramda';
import * as _mobx from 'mobx';

declare global {
  const R: typeof _R;
  const mobx: typeof _mobx;
}

In fact this file alone seems to "satisfy" the typescript compiler so in theory you wouldn't need the other files I mentioned previously. However in my particular case (I'm using WebStorm) when only having the globals.d.ts file my IDE was constantly pinging me to import the modules and also the completions on those globals were incomplete. So I basically kept now both files in the typings directory which satisfies typescript and my IDE. Not really nice, but for the few globals that one typically uses I guess it's ok to maintain those files.

This is my tsconfig.json for refence:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "amd",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "lib": [
      "ES6",
      "DOM",
      "ScriptHost"
    ],
    "sourceMap": true,
    "strictNullChecks": true
  },
  "include": [
    "types/**/*",
    "src/**/*"
  ]
}

I'm not using webpack or anything to bundle. I just transpile the individual files and load them via the https://github.com/SAP/openui5 module system (which is similar to AMD) and bundle them for production only.

Typescript version is : 2.2.1

Hope that helps.

All 11 comments

It isn't possible to do this because the minute you add an import declaration to a source file it is considered an external module. Any reason you're not using the React definition file that uses a global?

https://github.com/borisyankov/DefinitelyTyped/blob/master/react/react-global.d.ts

Looks to me like this would solve the problem.

I actually tried react-global.d.ts as well, which obviously puts React in the global space, but how would I globally rename it and let Typescript know about it?

declare var _r = React;  // error Cannot find name 'React';

My real use case would be to be able to hoist a utility/common type module to the global space so I don't have to use a bunch of relative path imports to get to it. I can do this in Javascript, but am struggling on how I let the Typescript compiler know I've done it.

@ahejlsberg -- I'm sure you have way more import things to be doing than putting up with my musings on edge cases... :)

You could for example create an r.d.ts declaration file:

/// <reference path="react-global.d.ts"/>
declare var R: typeof React;

and then just reference that file everywhere. Or even better:

/// <reference path="react-global.d.ts"/>
import R = React;

which will allow you to also reference types from React as R.xxx.

I've never seen a use of typeof before -- pretty cool. This works great for already defined modules from a .d.ts, but I still don't see a way to hoist an external module defined in Typescript to the global space and have Typescript know about it. Maybe because it's an anti-pattern and I should just get over it...

We've had a few requests (e.g. #2357) to extend typeof to support external modules, but so far there hasn't been a lot of demand for the feature.

Generally speaking, programs are either written without external modules or exclusively with external modules. Other than the bootstrap part of an AMD browser app, there really is no execution environment where the mixed model is even possible. So yes, it is mostly an anti-pattern.

Thanks for taking all the time to humor me on this! I've just started exploring external modules (to play with the upcoming Angular2 and Aurelia frameworks). Issues like #17, #2338 and #2839 seem to be more of what I'm looking for in the end. Hopefully I'll come up with clearer feedback as I dive deeper into my current project.

Is this still not possible to do? I'm trying to use TypeScript with VueJS and I would very much appreciate if I could import a few things into the global namespace so that all components can use it without having to import those things. Has there been any progress or hacks made to make this work?

@Evertt

I found a way which apparently works with typescript 2.x.x. In my case I want to expose the library ramda as global R.

  1. npm install ramda @types/ramda
  2. create file typings/ramda.d.ts
  3. add the newly created typings folder to the includes in .tsconfig.json:
"include": [
    "typings/**/*",
     ...
]
  1. add the magic to typings/ramda.d.ts:
import * as _R from 'ramda';

export as namespace R;
export = _R; 

Now all ts files in my project assume there's a typed global R without me doing any further imports or whatever in those files.

@geekflyer when I try to do that using the following code in my types/vue.d.ts:

import * as V from 'vue'

export as namespace Vue
export = V

I get the following error whenever I try to use that global Vue somewhere:

error TS2686: 'Vue' refers to a UMD global, but the current file is a module. Consider adding an import instead.

Did you get that error too at some point? If so, what did you do about it?

edit

If you don't get that error and you're not sure why I do get that error, would you maybe be willing to show me your entire tsconfig.json and maybe even your webpack config?

Hi @Evertt indeed I'm getting this error now too. Initially my source code wasn't using ES6 module syntax but once I refactored some files to that syntax I got the same error. Did some research and what worked for me now is when I create second file globals.d.ts and put it also into the typings folder:

import * as _R from 'ramda';
import * as _mobx from 'mobx';

declare global {
  const R: typeof _R;
  const mobx: typeof _mobx;
}

In fact this file alone seems to "satisfy" the typescript compiler so in theory you wouldn't need the other files I mentioned previously. However in my particular case (I'm using WebStorm) when only having the globals.d.ts file my IDE was constantly pinging me to import the modules and also the completions on those globals were incomplete. So I basically kept now both files in the typings directory which satisfies typescript and my IDE. Not really nice, but for the few globals that one typically uses I guess it's ok to maintain those files.

This is my tsconfig.json for refence:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "amd",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "lib": [
      "ES6",
      "DOM",
      "ScriptHost"
    ],
    "sourceMap": true,
    "strictNullChecks": true
  },
  "include": [
    "types/**/*",
    "src/**/*"
  ]
}

I'm not using webpack or anything to bundle. I just transpile the individual files and load them via the https://github.com/SAP/openui5 module system (which is similar to AMD) and bundle them for production only.

Typescript version is : 2.2.1

Hope that helps.

@geekflyer thank you that was very helpful

Was this page helpful?
0 / 5 - 0 ratings