jest-mock-extended icon indicating copy to clipboard operation
jest-mock-extended copied to clipboard

Deep mocking results in a TypeScript error + extreme compilation slowness

Open mklopets opened this issue 3 years ago • 8 comments
trafficstars

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;

mklopets avatar Jul 17 '22 13:07 mklopets

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

jnardone avatar Jul 18 '22 14:07 jnardone

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

zaniluca avatar Jul 20 '22 20:07 zaniluca

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.

atahanozbayram avatar Jul 27 '22 14:07 atahanozbayram

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

royhadad avatar Aug 01 '22 13:08 royhadad

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>)

xenoterracide avatar Aug 03 '22 22:08 xenoterracide

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

roblframpton avatar Aug 03 '22 23:08 roblframpton

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

wokkaflokka avatar Aug 04 '22 00:08 wokkaflokka

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

marchaos avatar Aug 11 '22 09:08 marchaos

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 avatar Sep 13 '22 14:09 marchaos

Fixed in 3.0.0

marchaos avatar Sep 16 '22 21:09 marchaos