Max Koretskyi
Max Koretskyi

Reputation: 105439

Merge namespaces inside `declare global` and `declare module`

I'm using Cypress for testing. In its support/commands.ts file I see the following:

declare module Cypress {
  interface Chainable<Subject> {
    login(email?: string, password?: string);
  }
}

This is the place where I add custom commands used on cy object Cypress.Commands.add('login',...) used like this cy.login().

Now I want to add 3rd party library that extends Cypress.Commands with the command matchImageSnapshot and defines types like this in @types/cypress-image-snapshot:

declare global {
    namespace Cypress {
        interface Chainable {
            matchImageSnapshot(nameOrOptions?: string | Options): void;
          }
    }
}

Once I import the command to support/commands.ts like this:

import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';

I get the error that commands defined in support/commands.ts are not valid:

TS2345: Argument of type '"logout"' is not assignable to parameter of type 'keyof Chainable '.

Based on some reading, I understand that using import in support/commands.ts turns this file into ES module (TS external module), right? And namespaces can't be merged between modules as I understand.

It also seems like the definition from @types/cypress-image-snapshot takes over the namespace declaration in support/commands.ts since if I add login command to the declaration in @types/cypress-image-snapshot the error is gone:

declare global {
    namespace Cypress {
        interface Chainable {
            matchImageSnapshot(nameOrOptions?: string | Options): void;

            login():void;  <----- my command from `support/commands.ts`
                                  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        }
    }
}

How do I solve this situation?

Upvotes: 0

Views: 1449

Answers (1)

Max Koretskyi
Max Koretskyi

Reputation: 105439

Found it. Based on this answer, that suggests that you can't merge namespaces between ES modules (external modules), it follows that you can't merge namespaces between global scope and a module.

It means that to fix the problem, declaration of both namespaces have to be in the global scope. So I had to wrap declare namespace Cypress {} in support/commands.ts into global scope like this:

declare global {
  namespace Cypress {
    interface Chainable<Subject> {
      login(email?: string, password?: string);
    }
  }
}

which solved the problem for me.

Upvotes: 3

Related Questions