New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[jest] add type inference #32579
[jest] add type inference #32579
Conversation
@antoinebrault Thank you for submitting this PR! 🔔 @JoshuaKGoldberg @tkrotoff @cwoodland @johnny4753 @NoHomey @jwbay @asvetliakov @alexjoverm @epicallan @ikatyang @wsmd @JamieMason @douglasduteil @ahnpnl @JoshuaKGoldberg @UselessPickles @r3nya @Hotell @sebald @andys8 @dawnmist @geovanisouza92 @deadNightTiger @joscha @jonasheinrich @aldentaylor @bradleyayers - please review this PR in the next few days. Be sure to explicitly select If no reviewer appears after a week, a DefinitelyTyped maintainer will review the PR instead. |
A definition owner has approved this PR ⭐️. A maintainer will merge this PR shortly. If it shouldn't be merged yet, please leave a comment saying so and we'll wait. Thank you for your contribution to DefinitelyTyped! |
@@ -11,8 +11,8 @@ function subtract(minuend: number, subtrahend: number) { | |||
} | |||
|
|||
beforeEach(() => { | |||
jest.spyOn(global, 'describe').mockImplementation((title, fn) => fn()); | |||
jest.spyOn(global, 'test').mockImplementation((name, fn) => fn()); | |||
jest.spyOn(global, 'describe').mockImplementation((title, fn) => jest.fn()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you comment on the change here? Is this because fn
is now correctly typed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know why I did that... I updated the PR.
fn
should be cast to a function because it is unknown
jest.spyOn(global, 'describe').mockImplementation((title, fn) => (fn as () => void)());
@@ -35,6 +36,8 @@ declare var xtest: jest.It; | |||
|
|||
declare const expect: jest.Expect; | |||
|
|||
type ArgsType<T> = T extends (...args: infer A) => any ? A : never; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TS ships with a Parameters
type for this. Was it added after 3.0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was added in 3.1 (microsoft/TypeScript@60b4fe9)
Thanks for the info. I didn't even know about it since it's not in https://www.typescriptlang.org/docs/handbook/advanced-types.html
ERROR: 218:145 expect Compile error in typescript@3.0 but not in typescript@3.1.
Fix with a comment '// TypeScript Version: 3.1' just under the header.
Cannot find name 'Parameters'.
types/jest/jest-tests.ts
Outdated
const spy6 = jest.spyOn(spiedTarget2, "value", "set"); | ||
|
||
let spy7: jest.SpyInstance; | ||
spy7 = jest.spyOn(spiedTarget, "setValue"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this one trying to test since nothing is done with spy7?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just testing if spyOn can be assigned to default generics of jest.SpyInstance. spy4 is basically the same. I'll remove spy7 from the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple questions, but everything looks shippable to me. Love all the $ExpectType
s in the tests.
I just published |
I just published |
I just published |
I just published |
I just published |
I just published |
I just published |
I just published |
I just published |
I just published |
The bot is becoming more clever 😮 Would be nice to just post a single time and edit the post as it progress, or only post once with the entire list: I just published to NPM
<details><summary>9/9 packages</summary>
``\`
...
@types/jest-when@1.1
@types/storybook__addon-storyshots@3.4
``\`
</details> I can see this being a problem should |
Yeah, something we could definitely improve. I'll talk to the team about it and see what can be done. Thanks for contributing. |
This update is absolutely fantastic. I am having a couple issues with the implementation though.
Here's a playground link to test it out: https://bit.ly/2WJN5F9 I also added some code below with a proper test syntax: Test case interface Something {
a: number;
}
class Api {
async performAction(x: Something): Promise<Something> { /* do whatever */ }
} api.spec.ts: jest.mock('./api.ts');
import { Api } from './api';
describe('Demo', () => {
let api: jest.Mocked<Api>;
beforeEach(() => {
api = new Api() as any;
})
it('should compile', () => {
api.performAction.mockImplementation(() => Promise.resolve({ a: 1 }));
api.performAction.mockReturnValue(Promise.resolve({ a: 2 }));
api.performAction.mockResolvedValue({ a: 3 });
});
}); Suggestion type Mocked<T> = {
[P in keyof T]: T[P] & MockInstance<T[P] extends (...args) => any ? ReturnType<T[P]> : T[P], ArgsType<T[P]>>;
} & T;
interface MockInstance<T, Y extends any[]> {
mockResolvedValue(value: T extends PromiseLike<infer U> ? U : never): Mock<T, Y>;
// same for resolvedOnce, reject, rejectOnce
} |
You're right. I'll look at it and add tests tonight.
type Mocked<T> = {
[P in keyof T]: T[P] extends (...args) => any ? MockInstance<ReturnType<T[P]>, ArgsType<T[P]>>: T[P];
} & T;
// considering this: await Promise.resolve(Promise.resolve(3)) === 3
mockResolvedValue(value: T extends PromiseLike<infer U> ? U | T : T | Promise<T>): Mock<T extends PromiseLike<any> ? T : Promise<T>, Y>; |
This is super awesome work - I had no idea TS would be able to infer as much as it's able to! 🎉 I'll be a bit sneaky and try to recruit help here. We're currently migrating Jest itself to TypeScript (jestjs/jest#7807), and I'd love some help converting |
Looks like this broke |
Follow-up of #31094
Updated jest typings to use latest typescript features to infer mock types.
Breaking Change
With types inferred, mockImplementation(), mockReturnValue(), mock...() will not compile if they are not used with the right types.
Please fill in this template.
npm test
.)npm run lint package-name
(ortsc
if notslint.json
is present).Select one of these and delete the others:
If changing an existing definition:
tslint.json
containing{ "extends": "dtslint/dt.json" }
.