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

perf(types): prevent immediate deep and circular resolution for deep mock #123

Merged
merged 2 commits into from Aug 3, 2023
Merged

perf(types): prevent immediate deep and circular resolution for deep mock #123

merged 2 commits into from Aug 3, 2023

Conversation

millsp
Copy link
Contributor

@millsp millsp commented Aug 2, 2023

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 under symbol. 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 that MockDeep 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 the PrismaClient. 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.

@millsp millsp marked this pull request as draft August 2, 2023 22:09
// 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;
Copy link
Contributor Author

@millsp millsp Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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]>;
} &
Copy link
Contributor Author

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;
Copy link
Contributor Author

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.

@marchaos
Copy link
Owner

marchaos commented Aug 3, 2023

Hey, @millsp - thanks for the PR, looks good! Just checking it locally and will merge if all good.

@marchaos marchaos merged commit 23279af into marchaos:master Aug 3, 2023
renovate bot added a commit to STORIS/mvom that referenced this pull request Aug 3, 2023
[![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://togithub.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://togithub.com/marchaos/jest-mock-extended/releases/tag/3.0.5)

[Compare
Source](https://togithub.com/marchaos/jest-mock-extended/compare/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**: 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>
@marchaos
Copy link
Owner

marchaos commented Aug 3, 2023

released in 3.0.5

@millsp
Copy link
Contributor Author

millsp commented Aug 3, 2023

Thanks!

renovate bot added a commit to tnez/starter-npm-pkg that referenced this pull request Aug 7, 2023
[![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://togithub.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node)
([source](https://togithub.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://togithub.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://togithub.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://togithub.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://togithub.com/marchaos/jest-mock-extended/releases/tag/3.0.5)

[Compare
Source](https://togithub.com/marchaos/jest-mock-extended/compare/3.0.4...3.0.5)

Fixed Deep Mock perf issue with
[marchaos/jest-mock-extended#123

</details>

<details>
<summary>prettier/prettier (prettier)</summary>

###
[`v3.0.1`](https://togithub.com/prettier/prettier/blob/HEAD/CHANGELOG.md#301)

[Compare
Source](https://togithub.com/prettier/prettier/compare/3.0.0...3.0.1)

[diff](https://togithub.com/prettier/prettier/compare/3.0.0...3.0.1)

##### Fix cursor positioning for a special case
([#&#8203;14812](https://togithub.com/prettier/prettier/pull/14812) by
[@&#8203;fisker](https://togithub.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
([#&#8203;15018](https://togithub.com/prettier/prettier/pull/15018) by
[@&#8203;kingyue737](https://togithub.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
([#&#8203;15037](https://togithub.com/prettier/prettier/pull/15037) by
[@&#8203;auvred](https://togithub.com/auvred))

<!-- prettier-ignore -->

```jsx
// Input
function fn() {
  return (
    /**
     * @&#8203;type {...}
     */ expresssion
  )
}

// Prettier 3.0.0
function fn() {
  return /**
   * @&#8203;type {...}
   */ expresssion;
}

// Prettier 3.0.1
function fn() {
  return (
    /**
     * @&#8203;type {...}
     */ expresssion
  );
}
```

##### Add support for Vue "Generic Components"
([#&#8203;15066](https://togithub.com/prettier/prettier/pull/15066) by
[@&#8203;auvred](https://togithub.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`
([#&#8203;15076](https://togithub.com/prettier/prettier/pull/15076) by
[@&#8203;fisker](https://togithub.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`
([#&#8203;15123](https://togithub.com/prettier/prettier/pull/15123) by
[@&#8203;so1ve](https://togithub.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`
([#&#8203;15125](https://togithub.com/prettier/prettier/pull/15125) by
[@&#8203;auvred](https://togithub.com/auvred))

```tsx
const printer: Printer = {
  print: () => [],
  getVisitorKeys(node, nonTraversableKeys) {
    return ["body"];
  },
};
```

##### Add typing to support `readonly` array properties of AST Node
([#&#8203;15127](https://togithub.com/prettier/prettier/pull/15127) by
[@&#8203;auvred](https://togithub.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
([#&#8203;15129](https://togithub.com/prettier/prettier/pull/15129) by
[@&#8203;pamelalozano](https://togithub.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://togithub.com/egoist/tsup/releases/tag/v7.2.0)

[Compare
Source](https://togithub.com/egoist/tsup/compare/v7.1.0...v7.2.0)

##### Bug Fixes

- allow to kill onSuccess process using SIGKILL signal, closes
[#&#8203;936](https://togithub.com/egoist/tsup/issues/936)
([612cabf](https://togithub.com/egoist/tsup/commit/612cabf1c1b99709d5d16c6e861ec12dae3db455))

##### Features

- add option for interop default in cjs
([#&#8203;947](https://togithub.com/egoist/tsup/issues/947))
([d870f4e](https://togithub.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://togithub.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>
Vylpes pushed a commit to Vylpes/random-bunny that referenced this pull request Sep 11, 2023
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>
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

Successfully merging this pull request may close these issues.

None yet

2 participants