-
Notifications
You must be signed in to change notification settings - Fork 59
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
perf(types): prevent immediate deep and circular resolution for deep mock #123
Conversation
// prevent immediate type resolution on a recursive type, this will | ||
// help to improve performance for deeply nested recursive mocking | ||
// at the same time, this intersection preserves private properties | ||
export type DeepMockProxy<T> = _DeepMockProxy<T> & T; |
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.
export type DeepMockProxy<T> = _DeepMockProxy<T> & T; | |
export type DeepMockProxy<T> = _DeepMockProxy<T> & T; |
In theory re-intersecting should not be necessary because we did already in the mapped types. But because the original type can contain private fields, using a mapped type on it erases that information. So the solution is to re-intersect once only.
// This supports deep mocks in the else branch | ||
[K in keyof T]: T[K] extends (...args: infer A) => infer B ? CalledWithMock<B, A> : DeepMockProxy<T[K]>; | ||
} & |
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.
This causes TypeScript to expand and immediately compute the type, potentially doing dangerous eager loading on deep and recursive or mutually self-referencing objects - potentially causing perf issues.
: DeepMockProxy<T[K]>; | ||
}; | ||
|
||
export type DeepMockProxyWithFuncPropSupport<T> = _DeepMockProxyWithFuncPropSupport<T> & T; |
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.
I did all of them for consistency.
Hey, @millsp - thanks for the PR, looks good! Just checking it locally and will merge if all good. |
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [jest-mock-extended](https://github.com/marchaos/jest-mock-extended) | [`3.0.4` -> `3.0.5`](https://renovatebot.com/diffs/npm/jest-mock-extended/3.0.4/3.0.5) | [![age](https://developer.mend.io/api/mc/badges/age/npm/jest-mock-extended/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/jest-mock-extended/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/jest-mock-extended/3.0.4/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jest-mock-extended/3.0.4/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>marchaos/jest-mock-extended (jest-mock-extended)</summary> ### [`v3.0.5`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.5) [Compare Source](https://github.com/marchaos/jest-mock-extended/compare/3.0.4...3.0.5) Fixed Deep Mock perf issue with [https://github.com/marchaos/jest-mock-extended/pull/123](https://github.com/marchaos/jest-mock-extended/pull/123) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR is behind base branch, 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 [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/STORIS/mvom). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi4yNy4xIiwidXBkYXRlZEluVmVyIjoiMzYuMjcuMSIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
released in 3.0.5 |
Thanks! |
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node) ([source](https://github.com/DefinitelyTyped/DefinitelyTyped)) | [`20.4.5` -> `20.4.8`](https://renovatebot.com/diffs/npm/@types%2fnode/20.4.5/20.4.8) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/20.4.8?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2fnode/20.4.8?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2fnode/20.4.5/20.4.8?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/20.4.5/20.4.8?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [jest-mock-extended](https://github.com/marchaos/jest-mock-extended) | [`3.0.4` -> `3.0.5`](https://renovatebot.com/diffs/npm/jest-mock-extended/3.0.4/3.0.5) | [![age](https://developer.mend.io/api/mc/badges/age/npm/jest-mock-extended/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/jest-mock-extended/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/jest-mock-extended/3.0.4/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jest-mock-extended/3.0.4/3.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [prettier](https://prettier.io) ([source](https://github.com/prettier/prettier)) | [`3.0.0` -> `3.0.1`](https://renovatebot.com/diffs/npm/prettier/3.0.0/3.0.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/prettier/3.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/prettier/3.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/prettier/3.0.0/3.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/prettier/3.0.0/3.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [tsup](https://tsup.egoist.dev/) ([source](https://github.com/egoist/tsup)) | [`7.1.0` -> `7.2.0`](https://renovatebot.com/diffs/npm/tsup/7.1.0/7.2.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/tsup/7.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/tsup/7.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/tsup/7.1.0/7.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/tsup/7.1.0/7.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>marchaos/jest-mock-extended (jest-mock-extended)</summary> ### [`v3.0.5`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.5) [Compare Source](https://github.com/marchaos/jest-mock-extended/compare/3.0.4...3.0.5) Fixed Deep Mock perf issue with [https://github.com/marchaos/jest-mock-extended/pull/123](https://github.com/marchaos/jest-mock-extended/pull/123) </details> <details> <summary>prettier/prettier (prettier)</summary> ### [`v3.0.1`](https://github.com/prettier/prettier/blob/HEAD/CHANGELOG.md#301) [Compare Source](https://github.com/prettier/prettier/compare/3.0.0...3.0.1) [diff](https://github.com/prettier/prettier/compare/3.0.0...3.0.1) ##### Fix cursor positioning for a special case ([#​14812](https://github.com/prettier/prettier/pull/14812) by [@​fisker](https://github.com/fisker)) <!-- prettier-ignore --> ```js // <|> is the cursor position /* Input */ // All messages are represented in JSON. // So, the prettier.py controls a subprocess which spawns "node {this_file}". import {<|> } from "fs" /* Prettier 3.0.0 */ // All messages are represented in JSON. // So, the prettier.py <|>controls a subprocess which spawns "node {this_file}". import {} from "fs" /* Prettier 3.0.1 */ // All messages are represented in JSON. // So, the prettier.py controls a subprocess which spawns "node {this_file}". import {<|>} from "fs" ``` ##### Fix plugins/estree.d.ts to make it a module ([#​15018](https://github.com/prettier/prettier/pull/15018) by [@​kingyue737](https://github.com/kingyue737)) Add `export {}` in `plugins/estree.d.ts` to fix the "File is not a module" error ##### Add parenthesis around leading multiline comment in return statement ([#​15037](https://github.com/prettier/prettier/pull/15037) by [@​auvred](https://github.com/auvred)) <!-- prettier-ignore --> ```jsx // Input function fn() { return ( /** * @​type {...} */ expresssion ) } // Prettier 3.0.0 function fn() { return /** * @​type {...} */ expresssion; } // Prettier 3.0.1 function fn() { return ( /** * @​type {...} */ expresssion ); } ``` ##### Add support for Vue "Generic Components" ([#​15066](https://github.com/prettier/prettier/pull/15066) by [@​auvred](https://github.com/auvred)) https://blog.vuejs.org/posts/vue-3-3#generic-components <!-- prettier-ignore --> ```vue <!-- Input --> <script setup lang="ts" generic="T extends Type1 & Type2 & (Type3 | Type4), U extends string | number | boolean"></script> <!-- Prettier 3.0.0 --> <script setup lang="ts" generic="T extends Type1 & Type2 & (Type3 | Type4), U extends string | number | boolean" ></script> <!-- Prettier 3.0.1 --> <script setup lang="ts" generic=" T extends Type1 & Type2 & (Type3 | Type4), U extends string | number | boolean " ></script> ``` ##### Fix comments print in `IfStatement` ([#​15076](https://github.com/prettier/prettier/pull/15076) by [@​fisker](https://github.com/fisker)) <!-- prettier-ignore --> ```js function a(b) { if (b) return 1; // comment else return 2; } /* Prettier 3.0.0 */ Error: Comment "comment" was not printed. Please report this error! /* Prettier 3.0.1 */ function a(b) { if (b) return 1; // comment else return 2; } ``` ##### Add missing type definition for `printer.preprocess` ([#​15123](https://github.com/prettier/prettier/pull/15123) by [@​so1ve](https://github.com/so1ve)) ```diff export interface Printer<T = any> { // ... + preprocess?: + | ((ast: T, options: ParserOptions<T>) => T | Promise<T>) + | undefined; } ``` ##### Add missing `getVisitorKeys` method type definition for `Printer` ([#​15125](https://github.com/prettier/prettier/pull/15125) by [@​auvred](https://github.com/auvred)) ```tsx const printer: Printer = { print: () => [], getVisitorKeys(node, nonTraversableKeys) { return ["body"]; }, }; ``` ##### Add typing to support `readonly` array properties of AST Node ([#​15127](https://github.com/prettier/prettier/pull/15127) by [@​auvred](https://github.com/auvred)) <!-- prettier-ignore --> ```tsx // Input interface TestNode { readonlyArray: readonly string[]; } declare const path: AstPath<TestNode>; path.map(() => "", "readonlyArray"); // Prettier 3.0.0 interface TestNode { readonlyArray: readonly string[]; } declare const path: AstPath<TestNode>; path.map(() => "", "readonlyArray"); // ^ Argument of type '"readonlyArray"' is not assignable to parameter of type '"regularArray"'. ts(2345) // Prettier 3.0.1 interface TestNode { readonlyArray: readonly string[]; } declare const path: AstPath<TestNode>; path.map(() => "", "readonlyArray"); ``` ##### Add space before unary minus followed by a function call ([#​15129](https://github.com/prettier/prettier/pull/15129) by [@​pamelalozano](https://github.com/pamelalozano)) <!-- prettier-ignore --> ```less // Input div { margin: - func(); } // Prettier 3.0.0 div { margin: -func(); } // Prettier 3.0.1 div { margin: - func(); } ``` </details> <details> <summary>egoist/tsup (tsup)</summary> ### [`v7.2.0`](https://github.com/egoist/tsup/releases/tag/v7.2.0) [Compare Source](https://github.com/egoist/tsup/compare/v7.1.0...v7.2.0) ##### Bug Fixes - allow to kill onSuccess process using SIGKILL signal, closes [#​936](https://github.com/egoist/tsup/issues/936) ([612cabf](https://github.com/egoist/tsup/commit/612cabf1c1b99709d5d16c6e861ec12dae3db455)) ##### Features - add option for interop default in cjs ([#​947](https://github.com/egoist/tsup/issues/947)) ([d870f4e](https://github.com/egoist/tsup/commit/d870f4e76cf0ff89a83e90bdc4931aa30bddb536)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - "before 4am on Monday" (UTC). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/tnez/starter-npm-pkg). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi4yNy4xIiwidXBkYXRlZEluVmVyIjoiMzYuMjcuMSIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [jest-mock-extended](https://github.com/marchaos/jest-mock-extended) | devDependencies | patch | [`3.0.4` -> `3.0.5`](https://renovatebot.com/diffs/npm/jest-mock-extended/3.0.4/3.0.5) | --- ### Release Notes <details> <summary>marchaos/jest-mock-extended (jest-mock-extended)</summary> ### [`v3.0.5`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.5) [Compare Source](marchaos/jest-mock-extended@3.0.4...3.0.5) Fixed Deep Mock perf issue with marchaos/jest-mock-extended#123 </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:eyJjcmVhdGVkSW5WZXIiOiIzNi44OS4wIiwidXBkYXRlZEluVmVyIjoiMzYuODkuMCIsInRhcmdldEJyYW5jaCI6ImRldmVsb3AifQ==--> Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/random-bunny/pulls/83 Co-authored-by: Renovate Bot <renovate@vylpes.com> Co-committed-by: Renovate Bot <renovate@vylpes.com>
Hey @marchaos 👋, a user has opened this issue in Prisma, and after further investigation I pinned the performance issue to come from the
MockDeep
types provided here. We recently introduced meta types that are hidden undersymbol
. There's noting special about these types except that they can be very deep and recursive, but it's all objects/records in the end. I found thatMockDeep
caused/forced TypeScript to evaluate these types.While this is not obvious, any intersection on a mapped type (eg. compute) itself will cause the mapped type to be resolved, otherwise TS would defer that for later (eg. when you access it). So
MockDeep
was forcing resolution on very huge and recursive types in thePrismaClient
. This PR does not make things easier to read, but does make things more efficient, by forcing resolution within the mapped type itself. Also I had to re-intersect with the original type as well to preserve the full shape, including private props which mapped types remove.With that, I was able to compile a huge PrismaClient like before we introduced this special type metadata on the
symbol
key.