Skip to content
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

The simplified MockInstance<T> type does not work with function overloads #6085

Closed
6 tasks done
xsjcTony opened this issue Jul 11, 2024 · 5 comments · Fixed by #6086
Closed
6 tasks done

The simplified MockInstance<T> type does not work with function overloads #6085

xsjcTony opened this issue Jul 11, 2024 · 5 comments · Fixed by #6086

Comments

@xsjcTony
Copy link
Contributor

xsjcTony commented Jul 11, 2024

Describe the bug

It won't work with function overloads, refer to the reproduction.

Reproduction

type error in v2
https://stackblitz.com/edit/vitest-dev-vitest-hlq3zj?file=test%2Fbasic.test.ts

No type error in v1, but seems the other overload signature is being ignored
https://stackblitz.com/edit/vitest-dev-vitest-cayu3q?file=test%2Fbasic.test.ts

System Info

System:
    OS: Windows 11 10.0.22631
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
    Memory: 7.79 GB / 31.69 GB
  Binaries:
    Node: 20.11.0 - C:\Program Files\nodejs\node.EXE
    npm: 10.8.1 - C:\Program Files\nodejs\npm.CMD
    pnpm: 9.5.0 - ~\AppData\Local\pnpm\pnpm.EXE
  Browsers:
    Edge: Chromium (126.0.2592.87)
    Internet Explorer: 11.0.22621.3527

Used Package Manager

npm

Validations

@xsjcTony xsjcTony changed the title The simplified Mock<T> type does not work with function overloads The simplified MockInstance<T> type does not work with function overloads Jul 11, 2024
@hi-ogawa
Copy link
Contributor

Thanks for the report. I haven't thought about this case.

Similar code on Jest has no type errors, but it looks like it still has some limitations with function overloads.

test("overload", () => {
  // they have dedicated `Spied` type to align `spyOn` return type.
  // so assignment works fine
  let spy: jest.Spied<Element["scrollTo"]>
  spy = jest.spyOn(Element.prototype, "scrollTo");

  // but only 2nd overload argument types
  spy.mock.calls satisfies [x: number, y: number][];

 
  // for `Mock`, probably Vitest and Jest work same.
  let mockFn: jest.Mock<Element["scrollTo"]>;
  mockFn = jest.fn(Element.prototype.scrollTo);
  
  mockFn(0, 1); // 2nd overload ok
  
  // @ts-expect-error
  mockFn({ top: 0 }); // 1st overload error
})

Probably this comes down to Parameters picking up only one of the overload

type OverloadFn = {
  (x: number, y: number): void;
  (someOptions?: { top?: number }): void;
}

// this becomes `[x: number, y: number]`
type OverloadArgs = Parameters<Element["scrollTo"]>

@xsjcTony
Copy link
Contributor Author

That's true. Like I provided above, even in v1, because that I'm using Parameters<T> manually, hence there's no type error because only 1 overload is picked up, but truly it is the limitation, since .mockImplementation() won't support another overload in that case.

@xsjcTony
Copy link
Contributor Author

xsjcTony commented Jul 11, 2024

Seems like a hard limitation there, emmm,..... 🤦‍♀️
image

See this also: microsoft/TypeScript#32164 (comment)

@xsjcTony
Copy link
Contributor Author

But I think at least we should try to find a way to avoid the type error there, and maybe document the TS limitation on function overloads

@hi-ogawa
Copy link
Contributor

hi-ogawa commented Jul 11, 2024

This type mismatch is probably because we split types here MockInstance<(this: R, ...args: A) => R>. If we can somehow preserve it as MockInstance<T[M]>, then typescript won't probably complain.

export function spyOn<T, M extends Classes<Required<T>> | Methods<Required<T>>>(
obj: T,
methodName: M
): Required<T>[M] extends
| { new (...args: infer A): infer R }
| ((...args: infer A) => infer R)
? MockInstance<(this: R, ...args: A) => R>
: never

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
2 participants