Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow module definitions to be declared as global variables #3180

Closed
dfaivre opened this issue May 15, 2015 · 11 comments
Closed

Allow module definitions to be declared as global variables #3180

dfaivre opened this issue May 15, 2015 · 11 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@dfaivre
Copy link

dfaivre commented May 15, 2015

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?

@ahejlsberg
Copy link
Member

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.

@ahejlsberg ahejlsberg added the Question An issue which isn't directly actionable in code label May 15, 2015
@dfaivre
Copy link
Author

dfaivre commented May 15, 2015

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... :)

@ahejlsberg
Copy link
Member

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.

@dfaivre
Copy link
Author

dfaivre commented May 18, 2015

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...

@ahejlsberg
Copy link
Member

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.

@dfaivre
Copy link
Author

dfaivre commented May 18, 2015

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.

@Evertt
Copy link

Evertt commented Jan 19, 2017

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?

@geekflyer
Copy link

geekflyer commented Feb 28, 2017

@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.

@Evertt
Copy link

Evertt commented Feb 28, 2017

@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?

@geekflyer
Copy link

geekflyer commented Feb 28, 2017

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.

@Evertt
Copy link

Evertt commented Feb 28, 2017

@geekflyer thank you that was very helpful

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants