Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you expose class in a module to the global namespace in TypeScript?

The Problem

Given

  • I have an existing application containing both modules and global scripts (regular non-module scripts).
    • modules
      • App.ts
    • global scripts
      • alpha.ts contains a class named alpha
      • beta.ts contains a class named beta
      • gamma.ts contains a class named gamma
  • I want to convert one class in a global script (gamma.ts) into a module
    • via adding export default before class gamma {} in gamma.ts
  • I want to import class gamma into the global namespace (i.e the window object) so it can be accessed by the existing global and module scripts.

What I have tried

I have tried a bunch of things around global.d.ts

e.g.

import gammaAlias from "../scripts/gamma";
export as namespace NS_Global;

declare global {
    var qqq: {n:string};
    namespace ZZZ {
       export var gamma: gammaAlias;
    }
    var gamma: gammaAlias;
}

But none has worked

i.e. TypeScript tells me one of the following

  • gamma does not exist
  • Cannot use 'new' with an expression whose type lacks a call or construct signature.

github

I have a github repo set up to investigate these questions. https://github.com/penguin020/expose-typescript-modules-globally

ConvertToModulesPOC_original is the working "before" case.

ConvertToModulesPOC is a broken attempt to convert gamma .ts to a module and expose it globally.

PS

The question remains, how do you expose a module to the global namespace?

Any answers using the examples in the github would be particularly appreciated!

like image 376
bnieland Avatar asked Nov 22 '19 19:11

bnieland


People also ask

How can we access a class of module from outside in TypeScript?

Modules are a way to create a local scope in the file. So, all variables, classes, functions, etc. that are declared in a module are not accessible outside the module. A module can be created using the keyword export and a module can be used in another module using the keyword import .

What is the difference between namespace and module in TypeScript?

A module is a way which is used to organize the code in separate files and can execute in their local scope, not in the global scope. A namespace is a way which is used for logical grouping of functionalities with local scoping.

How do you define a namespace in TypeScript?

We can create a namespace by using the namespace keyword followed by the namespace_name. All the interfaces, classes, functions, and variables can be defined in the curly braces{} by using the export keyword. The export keyword makes each component accessible to outside the namespaces.

What are namespaces and modules in typescript?

Namespaces and Modules. A note about terminology: It’s important to note that in TypeScript 1.5, the nomenclature has changed. “Internal modules” are now “namespaces”. “External modules” are now simply “modules”, as to align with ECMAScript 2015’s terminology, (namely that module X { is equivalent to the now-preferred namespace X {).

What is type declare global in typescript?

declare global is what tells Typescript that any type declarations within are related to the global context, not to the current module (remember that the new file above is a module now, because of the top level import).

What is an external module in typescript?

“External modules” are now simply “modules”, as to align with ECMAScript 2015 ’s terminology, (namely that module X { is equivalent to the now-preferred namespace X { ). This post outlines the various ways to organize your code using namespaces (previously “internal modules”) in TypeScript.

What is the recommended code organization mechanism in typescript?

Thus, for new projects modules would be the recommended code organization mechanism. Namespaces are a TypeScript-specific way to organize code. Namespaces are simply named JavaScript objects in the global namespace.


2 Answers

I found an answer here in "TypeScript: exposing module types in the global context and why to avoid it";

I have updated the github repo.

The most salient changes I found were:


in tsconfig:

"module": "system",

in yMod.ts

import gammaAlias from "../scripts/gamma.js";

declare global {
    export type gamma = gammaAlias;
    export const gamma: typeof gammaAlias;
}

(window as any).gamma = gammaAlias;

note: You could have the global ambient declaration in another file, even a *.d.ts file.


The link above breaks down the reasons for having three references for each symbol to be exposed globally. It is pretty well explained on that page, so I will only summarize here:

  1. Expose the class type to the TypeScript compiler (no code generated)
  2. Expose the class object to the TypeScript compiler (so there is an object to call new on; no code generated)
  3. Extend the window object to expose the class in the global namespace (generates code).
like image 91
bnieland Avatar answered Oct 09 '22 12:10

bnieland


I hope I understood your question correctly. You want to expose 'gamma' to the global namespace so that you can call 'gamma.log()' straight from 'window' or from the console?

Add the following 2 lines into gamma.ts at the bottom of the class.

let g = new gamma();
(window as any).gamma = g

1) The first line initializes a new Gamma class into variable g.

2) The second line exports g into the global namespace so that it can be called from 'window.g' or simply just 'g'.

Screenshot

Pull request #1: https://github.com/penguin020/expose-typescript-modules-globally/pull/1/files


I also suggest moving these two lines of code into your main initialization file 'app.js'.

gamma.ts

export default class gamma {

app.ts

import gamma from "./gamma";
let g = new gamma();
(window as any).gamma = g

Pull request #2: https://github.com/penguin020/expose-typescript-modules-globally/pull/2

like image 1
aelesia Avatar answered Oct 09 '22 10:10

aelesia