Augmenting global scope in Typescript not working

Viewed 1093

to get some context I'm working in a microservices app where I have two similar services with practically the same packages. In order to make some testing I add a function to the global scope and augmented it to avoid typescript errors. The problem is that in one service is working with no errors and in the other no.

Here is the code:

import { MongoMemoryServer } from 'mongodb-memory-server';
import mongoose from 'mongoose';
import jwt from 'jsonwebtoken';

// --- This is not working
declare global {
    namespace NodeJS {
        interface Global {
            signup(id?: string): string[];
        }
    }
}
// ---

jest.mock('./../nats-wrapper.ts');

let mongo: any;

beforeAll(async () => {
    process.env.JWT_KEY = 'only_for_testing';

    mongo = new MongoMemoryServer();
    const mongoUri = await mongo.getUri();

    await mongoose.connect(mongoUri, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    });
});

beforeEach(async () => {
    jest.clearAllMocks();
    const collections = await mongoose.connection.db.collections();

    for (let collection of collections) {
        await collection.deleteMany({});
    }
});

afterAll(async () => {
    await mongo.stop();
    await mongoose.connection.close();
});

// --- This is not working
global.signup = (id?:string) => {
    // Build a JWT payload. {id, email}
    const payload = {
        id: id || new mongoose.Types.ObjectId().toHexString(),
        email: 'test@test.com',
    };

    // Create the JWT!
    const token = jwt.sign(payload, process.env.JWT_KEY!);

    // Build session Object
    const session = { jwt: token };

    // Turn sesion into JSON
    const sessionJSON = JSON.stringify(session);

    // Encode to Base64
    const base64 = Buffer.from(sessionJSON).toString('base64');

    // return a string with the enconded data;
    return [`express:sess=${base64}`];
};
// ---

And this is the error I'm getting: TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.

What I noticed, debugging the node_modelues (to see what is happening behind scenes), is that the {globals.global.d.ts} file is not updating with the declaration.

Working service globals.global.d.ts:

declare var global: NodeJS.Global & typeof globalThis;

Not working service globals.global.d.ts:

declare var global: typeof globalThis;

*Apologized in advanced if this is a silly error, I'm quite new to TS*

3 Answers

With @types/node version 16 and above the correct way to do this is via:

declare var signup(id?: string): string[];

You can just use declare var (normally in .d.ts file) to declare your custom augmentations to global.

Another example:

// eslint-disable-next-line no-var 
declare var __MONGOD__: import('mongodb-memory-server').MongoMemoryReplSet;

Note that you may need to disable your eslint autofix if it's changing var to let, because let won't work properly.

I don't if this is the approach but I solved this issue by adding @types/node as a dependency.

Here is the solution: -

As of node@16, the NodeJS.Global interface has been removed in favor of globalThis.

You can declare a new global variable in a module file as:

declare global {
  var NEW_GLOBAL: string;
}

In your case, it would be: -

declare global {
   var signup: (id?: string) => string[];
}

NOTE: variables must be declared as var, let or const.

You can now access the global.signup in any of the modules in your project

Related