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

Deep mocking results in a TypeScript error + extreme compilation slowness #97

Closed
mklopets opened this issue Jul 17, 2022 · 10 comments
Closed

Comments

@mklopets
Copy link

mklopets commented Jul 17, 2022

Upgrading to v2.0.7 (see original PR) from v2.0.6 seems to have brought in something fishy when using mockDeep. On a fresh install, TypeScript compilation is now ridiculously slow.

yarn tsc --noEmit

  • before: 1.5-3.5s
  • first compilation after upgrading to the new version: 200s (i.e. over 3 minutes)
  • follow-up compilations on 2.0.7: once again <4s

TypeScript v4.7.4, Node v16.14.2, jest v28.1.3, ts-jest 28.0.7, running on an M1 Pro chip

Reproducible example:

import { DeepMockProxy, mockDeep } from 'jest-mock-extended';

interface Thing {
  foo: {
    bar: () => void;
  };
}

export const mockThing: DeepMockProxy<Thing> = mockDeep<Thing>();

Not only is this excruciatingly slow (but only the first time), it also complains with a type error:

node_modules/jest-mock-extended/lib/Mock.d.ts:27:222 - error TS2536: Type 'K_1' cannot be used to index type 'T[K]'.

27 export declare const mockDeep: <T>(mockImplementation?: DeepPartial<T> | undefined) => { [K in keyof T]: T[K] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K] extends infer T_1 ? { [K_1 in keyof T_1]: T[K][K_1] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1] extends infer T_2 ? { [K_2 in keyof T_2]: T[K][K_1][K_2] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2] extends infer T_3 ? { [K_3 in keyof T_3]: T[K][K_1][K_2][K_3] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3] extends infer T_4 ? { [K_4 in keyof T_4]: T[K][K_1][K_2][K_3][K_4] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4] extends infer T_5 ? { [K_5 in keyof T_5]: T[K][K_1][K_2][K_3][K_4][K_5] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5] extends infer T_6 ? { [K_6 in keyof T_6]: T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends infer T_7 ? { [K_7 in keyof T_7]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends infer T_8 ? { [K_8 in keyof T_8]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends infer T_9 ? { [K_9 in keyof T_9]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends infer T_10 ? { [K_10 in keyof T_10]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & any & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5]>; } : never) & T[K][K_1][K_2][K_3][K_4] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4]>; } : never) & T[K][K_1][K_2][K_3] : DeepMockProxy<T[K][K_1][K_2][K_3]>; } : never) & T[K][K_1][K_2] : DeepMockProxy<T[K][K_1][K_2]>; } : never) & T[K][K_1] : DeepMockProxy<T[K][K_1]>; } : never) & T[K] : DeepMockProxy<T[K]>; } & T;
                                                                                                                                                                                                                                ~~~~~~~~~

node_modules/jest-mock-extended/lib/Mock.d.ts:27:2781 - error TS2536: Type 'K_1' cannot be used to index type 'T[K]'.

27 export declare const mockDeep: <T>(mockImplementation?: DeepPartial<T> | undefined) => { [K in keyof T]: T[K] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K] extends infer T_1 ? { [K_1 in keyof T_1]: T[K][K_1] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1] extends infer T_2 ? { [K_2 in keyof T_2]: T[K][K_1][K_2] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2] extends infer T_3 ? { [K_3 in keyof T_3]: T[K][K_1][K_2][K_3] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3] extends infer T_4 ? { [K_4 in keyof T_4]: T[K][K_1][K_2][K_3][K_4] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4] extends infer T_5 ? { [K_5 in keyof T_5]: T[K][K_1][K_2][K_3][K_4][K_5] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5] extends infer T_6 ? { [K_6 in keyof T_6]: T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends infer T_7 ? { [K_7 in keyof T_7]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends infer T_8 ? { [K_8 in keyof T_8]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends infer T_9 ? { [K_9 in keyof T_9]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends infer T_10 ? { [K_10 in keyof T_10]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & any & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5]>; } : never) & T[K][K_1][K_2][K_3][K_4] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4]>; } : never) & T[K][K_1][K_2][K_3] : DeepMockProxy<T[K][K_1][K_2][K_3]>; } : never) & T[K][K_1][K_2] : DeepMockProxy<T[K][K_1][K_2]>; } : never) & T[K][K_1] : DeepMockProxy<T[K][K_1]>; } : never) & T[K] : DeepMockProxy<T[K]>; } & T;
@jnardone
Copy link

seeing the same on 2.0.6->2.0.7 (node 16.16, TS 4.7.4)

@zaniluca
Copy link

Got the same problem too, for my case it was resolved by downgrading to 2.0.6

  • jest: "^28.1.3"
  • jest-mock-extended: "2.0.6",
  • node: 16.15.1

@atahanozbayram
Copy link

I agree I have found the same problem in my repository, using 2.0.4 is fine but 2.0.7 makes typescript compilation from 13 seconds to 630 seconds for me.

@royhadad
Copy link

royhadad commented Aug 1, 2022

happens to me with versions 2.0.7, 2.0.6, 2.0.4 - any ideas for another fix?

@xenoterracide
Copy link

same here

System:

  • OS: macOS 11.6.6
  • CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz

Binaries:

  • Node: 16.14.2 - /private/var/folders/xk/s3n8ww014pzbx2sn30ctz7000000gq/T/xfs-0e6f078f/node
  • Yarn: 3.2.1 - /private/var/folders/xk/s3n8ww014pzbx2sn30ctz7000000gq/T/xfs-0e6f078f/yarn
  • npm: 8.5.0 - ~/.asdf/plugins/nodejs/shims/npm
❯ yarn why typescript
├─ @cof/e1-devexchange-client@workspace:packages/devexchange-client
│  └─ typescript@patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=7ad353 (via patch:typescript@^4.7.4#~builtin<compat/typescript>)

@roblframpton
Copy link

roblframpton commented Aug 3, 2022

I am also experiencing this issue, although I am using the regular mock function, not mockDeep. For me the issue is also resolved by downgrading to 2.0.6.

You can see in the tsc tracer that the problem is with the following file, which it spends several minutes processing:

{"pid":1,"tid":1,"ph":"B","cat":"check","ts":9729602.199999848,"name":"checkSourceFile","args":{"path":"/[...]/node_modules/jest-mock-extended/lib/Mock.d.ts"}}

On version 2.0.6 it only takes a short time on this step, but on 2.0.7 it gets stuck.

Environment

Ubuntu 20.04.2 LTS on Windows 10 WSL
Node 16.15.1
npm 8.11.0
tsc version 4.7.4

@wokkaflokka
Copy link

wokkaflokka commented Aug 4, 2022

Observed this issue attempting to upgrade from 2.0.6 to 2.0.7 (along with painfully long compilation times).

node_modules/jest-mock-extended/lib/Mock.d.ts:27:2781 - error TS2536: Type 'K_1' cannot be used to index type 'T[K]'.

27 export declare const mockDeep: <T>(mockImplementation?: DeepPartial<T> | undefined) => { [K in keyof T]: T[K] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K] extends infer T_1 ? { [K_1 in keyof T_1]: T[K][K_1] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1] extends infer T_2 ? { [K_2 in keyof T_2]: T[K][K_1][K_2] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2] extends infer T_3 ? { [K_3 in keyof T_3]: T[K][K_1][K_2][K_3] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3] extends infer T_4 ? { [K_4 in keyof T_4]: T[K][K_1][K_2][K_3][K_4] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4] extends infer T_5 ? { [K_5 in keyof T_5]: T[K][K_1][K_2][K_3][K_4][K_5] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5] extends infer T_6 ? { [K_6 in keyof T_6]: T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6] extends infer T_7 ? { [K_7 in keyof T_7]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends infer T_8 ? { [K_8 in keyof T_8]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends infer T_9 ? { [K_9 in keyof T_9]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & (T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends infer T_10 ? { [K_10 in keyof T_10]: T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & any & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5][K_6] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5][K_6]>; } : never) & T[K][K_1][K_2][K_3][K_4][K_5] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4][K_5]>; } : never) & T[K][K_1][K_2][K_3][K_4] : DeepMockProxy<T[K][K_1][K_2][K_3][K_4]>; } : never) & T[K][K_1][K_2][K_3] : DeepMockProxy<T[K][K_1][K_2][K_3]>; } : never) & T[K][K_1][K_2] : DeepMockProxy<T[K][K_1][K_2]>; } : never) & T[K][K_1] : DeepMockProxy<T[K][K_1]>; } : never) & T[K] : DeepMockProxy<T[K]>; } & T;
     

Environment

Mac 12.4 (Ubuntu 20.04)
Node 16.15.0
npm 8.5.5
tsc version 4.7.4

@marchaos
Copy link
Owner

I'll try and get a fix for this, without breaking the functionality that added to the slowness.

@marchaos
Copy link
Owner

marchaos commented Sep 13, 2022

I've pushed a fix as version 3.0.0-beta1. This required a small breaking change, but I'd imagine for 99% of users this version should be backwards compatible with 2.0.x. If you were using mockDeep and you were mocking functions that also had props, you will need to use

mockDeep({ funcPropSupport: true });
or 
mockDeep({ funcPropSupport: true }, mockImplementation);

but expect the same performance issue / penalty if you need to use this.

It would be good to get some feedback on this 🙏🏽 . Once there's enough feedback that this issue is fixed, I'll push a 3.0.0

@marchaos
Copy link
Owner

Fixed in 3.0.0

Vylpes pushed a commit to Vylpes/Droplet that referenced this issue Sep 14, 2023
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [jest-mock-extended](https://github.com/marchaos/jest-mock-extended) | devDependencies | major | [`^2.0.4` -> `^3.0.0`](https://renovatebot.com/diffs/npm/jest-mock-extended/2.0.4/3.0.4) |

---

### Release Notes

<details>
<summary>marchaos/jest-mock-extended</summary>

### [`v3.0.4`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.4)

[Compare Source](marchaos/jest-mock-extended@3.0.3...3.0.4)

-   Updated jest dependencies
-   Updated typescript peerDependencies to allow for typescript 5.\*

### [`v3.0.3`](marchaos/jest-mock-extended@3.0.2...3.0.3)

[Compare Source](marchaos/jest-mock-extended@3.0.2...3.0.3)

### [`v3.0.2`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.2)

[Compare Source](marchaos/jest-mock-extended@3.0.1...3.0.2)

Added marchaos/jest-mock-extended#110

### [`v3.0.1`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.1)

[Compare Source](marchaos/jest-mock-extended@3.0.0...3.0.1)

Allow overriding calledWithFn - see marchaos/jest-mock-extended#96

### [`v3.0.0`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.0)

[Compare Source](marchaos/jest-mock-extended@3602a65...3.0.0)

-   Fixed performance issue for marchaos/jest-mock-extended#97. This required a small API change, hence the major version bump. Deep mocking functions with properties is still possible using

```typescript
mockDeep({ funcPropSupport: true });
```

however this comes with a recursive performance cost. We hope to address this in the future.

### [`v2.0.9`](marchaos/jest-mock-extended@c6fdf33...3602a65)

[Compare Source](marchaos/jest-mock-extended@c6fdf33...3602a65)

### [`v2.0.8`](marchaos/jest-mock-extended@2.0.7...c6fdf33)

[Compare Source](marchaos/jest-mock-extended@2.0.7...c6fdf33)

### [`v2.0.7`](https://github.com/marchaos/jest-mock-extended/releases/tag/2.0.7)

[Compare Source](marchaos/jest-mock-extended@2.0.6...2.0.7)

### Fixes

-   Fix DeepMockProxy type error for objects which are functions and have fields at the same time - marchaos/jest-mock-extended#95

### [`v2.0.6`](https://github.com/marchaos/jest-mock-extended/releases/tag/2.0.6)

[Compare Source](marchaos/jest-mock-extended@2.0.5...2.0.6)

Support for Jest 28

### [`v2.0.5`](https://github.com/marchaos/jest-mock-extended/releases/tag/2.0.5)

[Compare Source](marchaos/jest-mock-extended@2.0.4...2.0.5)

Fixes:

-   Explicitly Show DeepMockProxy<T> In Readme Example - marchaos/jest-mock-extended#86
-   Fix ESM support by avoiding export default as syntax - marchaos/jest-mock-extended#83
-   Fix TypeError thrown in mockReset/mockClear - marchaos/jest-mock-extended#81

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC43NC4yIiwidXBkYXRlZEluVmVyIjoiMzQuNzQuMiJ9-->

Co-authored-by: Renovate Bot <renovate@vylpes.com>
Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/Droplet/pulls/109
Reviewed-by: Vylpes <ethan@vylpes.com>
Co-authored-by: RenovateBot <renovate@vylpes.com>
Co-committed-by: RenovateBot <renovate@vylpes.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants