Skip to content

Allow module definitions to be declared as global variables #3180

Closed

Description

@dfaivre

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?

Activity

  1. ahejlsberg commented on May 15, 2015

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

  2. dfaivre commented on May 15, 2015

    @dfaivre
    Author

    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.

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

  3. ahejlsberg commented on May 15, 2015

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

  4. dfaivre commented on May 18, 2015

    @dfaivre
    Author

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

  5. ahejlsberg commented on May 18, 2015

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

  6. dfaivre commented on May 18, 2015

    @dfaivre
    Author

    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.

  7. Evertt commented on Jan 19, 2017

    @Evertt

    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?

  8. geekflyer commented on Feb 28, 2017

    @geekflyer

    Evert van Brussel (@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.

  9. Evertt commented on Feb 28, 2017

    @Evertt

    Christian Theilemann (@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?

  10. geekflyer commented on Feb 28, 2017

    @geekflyer

    Hi Evert van Brussel (@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.

  11. Evertt commented on Feb 28, 2017

    @Evertt

    Christian Theilemann (@geekflyer) thank you that was very helpful

  12. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions