Reputation: 14318
This question is similar to Can you limit the scope of a TypeScript global type? but a little different (though I would love an answer to it, as well).
In Jest, I want to do something like:
declare global {
namespace jest {
interface Matchers<R> {
toBeAwesome(this: Matchers<void, HTMLElement>): R;
}
}
}
export {};
expect.extend({
toBeAwesome() {
// ...
}
});
However, I only call extend
in that specific file, and therefore I do not want other test files to be able to access it. The declare global {}
bit seems to screw me over.
I've also tried something hacky:
declare const expect: jest.Expect & {
<T = any>(actual: T): jest.JestMatchers<T> & {
toBeSelected(this: jest.Matchers<void, HTMLElement>): void;
};
};
But the method won't even show up.
I also tried directly declaring namespace jest
outside of the global scope, but since jest
is a global namespace, it created a new namespace instead of augmenting the other.
Is it possible to scope an augmentation to a specific file and any file that imports it?
Upvotes: 4
Views: 2370
Reputation: 180
I think Typescript is picking up the Jest built-in functions first rather than your custom one. Try rearranging the order of the type composition instead:
declare const expect: {
<T = any>(actual: T): {
toBeSelected(this: jest.Matchers<void, HTMLElement>): void;
} & jest.JestMatchers<T>;
} & jest.Expect;
I tried your "hacky" solution first but this is the one that worked for me.
Upvotes: 0
Reputation: 2437
Another workaround if you're using explicit imports from @jest/globals
(rather than @types/jest
which makes the globals available to TS everywhere) is to modify the type of the imported version of expect
.
import { expect as _expect } from '@jest/globals';
const expect = _expect as unknown as {
<T = unknown>(actual: T): {
toBeAwesome(): void;
} & ReturnType<typeof _expect>;
} & typeof _expect;
As written (there might be a better way), this doesn't provide type verification for the actual thing passed to expect()
, but it at least makes the matcher available and limited to the current file.
You could also do this with global types (@types/jest
) by redeclaring expect
with a different name, e.g. const expectElement = expect as unknown as /* custom type */
.
Upvotes: 0
Reputation: 9335
I don't think you can limit the scope of an augmented type within the same package, but you could define your own expect function with the type you want:
Something like:
function expectElement(actual: HTMLEelement): ElementExpect {
return expect(actual) as any as ElementExpect
}
type ElementExpect = JestExpect & ElementMatchers
interface ElementMatchers<R = void> extends Matchers<void> {
toBeSelected(): R
}
Then, arguably your tests are more explicit:
it("should be awesome", () => {
expectElement(el).toBeAwesome()
})
Upvotes: 2