feat(@jest/expect): Expose type of actual to Matchers#13848
feat(@jest/expect): Expose type of actual to Matchers#13848SimenB merged 8 commits intojestjs:mainfrom
Conversation
Matchers isn't as typed as some users would like (see jestjs#13334, jestjs#13812). For users who want to customize it by extending the `Matchers` interface, it's useful to have access to the type of `actual` (the argument of `expect`) so you can do, say, ```ts interface Matchers<R, T> { toTypedEqual(expected: T): R } ``` This commit exposes it. The first-party matchers still have the same types as before.
There was a problem hiding this comment.
Thanks! I think this is useful for custom matchers in general. For example, the inferred type of actual is used in snapshot matchers through @jest/expect. I think user of expect should be allowed to have similar functionality for a custom matcher.
Also because this was allowed before #12404 and still works with @types/jest. That's why I see this PR as a fix of a regression.
Could you add:
type N = Matchers<void, string>;Under this line:
Also please add a type test with your example of toTypedEqual here (simply to prevent regression):
|
|
||
| ### Features | ||
|
|
||
| - `[@jest/expect]` provide type of `actual` as a generic argument to `Matchers` to allow better-typed extensions (#TBD) |
There was a problem hiding this comment.
I think this can go under fixes as well.
| - `[@jest/expect]` provide type of `actual` as a generic argument to `Matchers` to allow better-typed extensions (#TBD) | |
| - `[expect, @jest/expect]` Provide type of `actual` as a generic argument to `Matchers` to allow better-typed extensions ([#13848](https://github.com/facebook/jest/pull/13848)) |
|
Thanks for all the helpful comments! I think I've addressed all of them. A couple notes:
|
Co-authored-by: Tom Mrazauskas <[email protected]>
Co-authored-by: Tom Mrazauskas <[email protected]>
| // @ts-expect-error unused variable T (can't use _T since users redeclare Matchers) | ||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| export interface Matchers<R extends void | Promise<void>, T = unknown> { |
There was a problem hiding this comment.
What about this:
| // @ts-expect-error unused variable T (can't use _T since users redeclare Matchers) | |
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | |
| export interface Matchers<R extends void | Promise<void>, T = unknown> { | |
| export interface Matchers<R extends void | Promise<void>, T = unknown> { | |
| /** @internal */ | |
| _doKeepT(expect: T): R; |
There was a problem hiding this comment.
Could have some longer comment, but seems to be working. Or?
stripInternal documentation: https://www.typescriptlang.org/tsconfig#stripInternal
There was a problem hiding this comment.
Ah, great! I thought of adding a fake method but didn't realize I could hide it like that.
mrazauskas
left a comment
There was a problem hiding this comment.
Two last details from my side. The rest looks good.
Type tests are passing, because emitted types keep T as expected:
It is marked as unused in this screenshot of .d.ts file. So I went checking if that is not a problem for a user having "skipLibCheck": true in a tsconfig.json. TypeScript did not complain. Seems to be fine.
Co-authored-by: Tom Mrazauskas <[email protected]>
Thanks for checking, I looked at the |
Co-authored-by: Tom Mrazauskas <[email protected]>
Yes, |
|
|
|
Right, |
|
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |

Summary
Matchers isn't as typed as some users would like (see #13334, #13812). For users who want to customize it by extending the
Matchersinterface, it's useful to have access to the type ofactual(the argument ofexpect) so you can do, say,This commit exposes it. The first-party matchers still have the same types as before.
Test Plan
typecheck