diff --git a/CHANGELOG.md b/CHANGELOG.md index d559084a4e5d..a9e9d7dee890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[expect, @jest/expect]` support type inference for `toBe` assertions ([#13470](https://github.com/facebook/jest/pull/13470)) - `[@jest/globals, jest-mock]` Add `jest.Spied*` utility types ([#13440](https://github.com/facebook/jest/pull/13440)) ### Fixes diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index e2fc979165ff..251861bfc1b0 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -94,9 +94,9 @@ export interface BaseExpect { } export type Expect = { - (actual: T): Matchers & + (actual: T): Matchers & Inverse> & - PromiseMatchers; + PromiseMatchers; } & BaseExpect & AsymmetricMatchers & Inverse>; @@ -118,7 +118,7 @@ export interface AsymmetricMatchers { stringMatching(sample: string | RegExp): AsymmetricMatcher; } -type PromiseMatchers = { +type PromiseMatchers = { /** * Unwraps the reason of a rejected promise so any other matcher can be chained. * If the promise is fulfilled the assertion fails. @@ -128,10 +128,11 @@ type PromiseMatchers = { * Unwraps the value of a fulfilled promise so any other matcher can be chained. * If the promise is rejected the assertion fails. */ - resolves: Matchers> & Inverse>>; + resolves: Matchers, Awaited> & + Inverse>>; }; -export interface Matchers> { +export interface Matchers, T = unknown> { /** * Ensures the last call to a mock function was provided specific args. */ @@ -152,7 +153,7 @@ export interface Matchers> { * Checks that a value is what you expect. It calls `Object.is` to compare values. * Don't use `toBe` with floating-point numbers. */ - toBe(expected: unknown): R; + toBe(expected: T): R; /** * Ensures that a mock function is called. */ diff --git a/packages/jest-expect/src/types.ts b/packages/jest-expect/src/types.ts index 10739da8481e..01122d2fe839 100644 --- a/packages/jest-expect/src/types.ts +++ b/packages/jest-expect/src/types.ts @@ -29,7 +29,10 @@ type Inverse = { not: Matchers; }; -type JestMatchers, T> = Matchers & +type JestMatchers, T = unknown> = Matchers< + R, + T +> & SnapshotMatchers; type PromiseMatchers = { @@ -37,14 +40,13 @@ type PromiseMatchers = { * Unwraps the reason of a rejected promise so any other matcher can be chained. * If the promise is fulfilled the assertion fails. */ - rejects: JestMatchers, T> & - Inverse, T>>; + rejects: JestMatchers> & Inverse>>; /** * Unwraps the value of a fulfilled promise so any other matcher can be chained. * If the promise is rejected the assertion fails. */ - resolves: JestMatchers, T> & - Inverse, T>>; + resolves: JestMatchers, Awaited> & + Inverse>>; }; declare module 'expect' { diff --git a/packages/jest-types/__typetests__/expect.test.ts b/packages/jest-types/__typetests__/expect.test.ts index 79b68993379b..7ca8779ed978 100644 --- a/packages/jest-types/__typetests__/expect.test.ts +++ b/packages/jest-types/__typetests__/expect.test.ts @@ -221,6 +221,11 @@ expectType( ), ); +expectType( + expect({age: 12, name: 'someName'}).toBe({age: 13, name: 'someOtherName'}), +); +expectError(expect({age: 12, name: 'someName'}).toBe({name: 'someOtherName'})); + expectType(expect(jest.fn()).toHaveBeenCalledWith()); expectType(expect(jest.fn()).toHaveBeenCalledWith(123)); expectType(expect(jest.fn()).toHaveBeenCalledWith(123, 'value'));