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

Memory Leak / Infinite Recursion. TS hangs, TSC never finishes, VSCode and Intellisense dies. #56081

Open
theonlydaleking opened this issue Oct 12, 2023 · 8 comments · May be fixed by #56165
Open
Assignees
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@theonlydaleking
Copy link

🔎 Search Terms

Typescript Hangs, Memory Leak, VS Code, Prisma, React-Hook-Form,

🕗 Version & Regression Information

  • This is a crash

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about hanging.

Tested on latest 5.2.2 and 5.3.0-dev-20231012. typescript@next

⏯ Playground Link

https://codesandbox.io/p/sandbox/musing-turing-78vp6j?file=%2Fapp%2Fpage.tsx%3A6%2C33

💻 Code

import { useForm } from "react-hook-form";
import { Prisma } from "@prisma/client";

export default function Home() {
  const form = useForm<Prisma.UserCreateInput>();
  ...

This will hang everything. Typescript won't tsc and intellisense will just sit with "loading" no matter what you hover.

meanwhile this works fine:

import { useForm } from "react-hook-form";
import { Prisma } from "@prisma/client";

export default function Home() {
  const form = useForm<>();
  ...

tsc --noEmit --extendedDiagnostics will complete in like 3 seconds with this.

🙁 Actual behavior

Typescript won't complete a tsc --noEmit and intellisense will just sit with "loading" no matter what you hover over. I have seen it once before just set everything to any

With the generated types in the first example - i let it run for 1 hour 59mins on a M1 mac and no output.

You can see the full code example with a minimal repro on the codesandbox link. It also hangs it's intellisense in CSB and won't tsc.
CPU also goes to 100% on both local and CSB

🙂 Expected behavior

Doesn't hang typescript, operates just like if you put any other type in there say

type SomeType = {name: string} 
const form = useForm<SomeType>() 

Additional information about the issue

Another report by someone else here:

https://stackoverflow.com/questions/76932600/high-cpu-usage-when-using-some-prisma-types-with-react-hook-form

It seems to be anything that comes off the Prisma.* types

@Pyrolistical
Copy link

Pyrolistical commented Oct 13, 2023

I found the provided codesandbox hard to use as the generated prisma client not included. I've extracted the generated client and put it into .app/client

Also to note, the repo description in this issue is incomplete. A call to form.register is required for tsc to stall.

Here is a much smaller repo https://github.com/Pyrolistical/typescript-repo-56081

npm run build never completes.

I started to cut down app/client/index.d.ts, but I gave up after seeing how complicated it is. Also as I cut it down, I noticed tsc does complete. So the extremely recursively types is just really hard for tsc process.

@PranavSenthilnathan
Copy link
Member

Thanks, I was able to repro this. It does look like the prisma generated types have complex template strings so tsc is spending a lot of time in removeStringLiteralsMatchedByTemplateLiterals and GC. I'll take a look into if we can cut off computation earlier and/or make the checking smarter.

@PranavSenthilnathan
Copy link
Member

Repro without library dependencies (I think the react-hook-form types can be simplified more, but this is a good point for me to start investigating from). Prisma generates deeply nested types with a depth of 10+ and branching at each node from 0 to 6+ (not a balanced tree). Still, the type below roughly approximates that and has the same perf issue.

declare var check : Check<t7>;
check("x.y.z.x.y.z.42");

type rec<t> = t | { [K in 'x' | 'y' | 'z' ]? : t }

type t1 = number[]
type t2 = rec<t1>
type t3 = rec<t2>
type t4 = rec<t3>
type t5 = rec<t4>
type t6 = rec<t5>
type t7 = rec<t6>
type t8 = rec<t7>
type t9 = rec<t8>

// From npm package 'react-hook-form'
type Primitive = number;
type ArrayKey = number;
type IsEqual<T1, T2> = T1 extends T2 ? (<G>() => G extends T1 ? 1 : 2) extends <G>() => G extends T2 ? 1 : 2 ? true : false : false;
type AnyIsEqual<T1, T2> = T1 extends T2 ? IsEqual<T1, T2> extends true ? true : never : never;

type PathImpl<K extends string | number, V, TraversedTypes> = V extends Primitive ? `${K}` : true extends AnyIsEqual<TraversedTypes, V> ? `${K}` : `${K}` | `${K}.${PathInternal<V, TraversedTypes | V>}`;
type PathInternal<T, TraversedTypes = T> = T extends ReadonlyArray<infer V> ? PathImpl<ArrayKey, V, TraversedTypes> : {
    [K in keyof T]-?: PathImpl<K & string, T[K], TraversedTypes>;
}[keyof T];

type Path<T> = T extends any ? PathInternal<T> : never;
type FieldPath<TFieldValues extends FieldValues> = Path<TFieldValues>;
type FieldValues = Record<string, any>;
type Check<TFieldValues extends FieldValues> = <TFieldName extends FieldPath<TFieldValues>>(name: TFieldName) => any;

Some stats (for Check<t7>, Check<t8> and Check<t9> respectively):

> npx tsc   
Types:                       2961
Instantiations:             14289
Memory used:               65308K
Check time:                 0.33s
Total time:                 0.71s
> npx tsc
Types:                       7666
Instantiations:             29755
Memory used:               79697K
Check time:                 2.12s
Total time:                 2.49s
> npx tsc
Types:                      21439
Instantiations:             63291
Memory used:               82899K
Check time:                20.45s
Total time:                20.83s

@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Oct 20, 2023
@jakebailey
Copy link
Member

jakebailey commented Oct 20, 2023

Does this bisect to #48044? (https://www.npmjs.com/package/every-ts may be helpful to check, too)

also #52345

@PranavSenthilnathan
Copy link
Member

It's this PR which introduces string literal and template literal reduction in unions (every-ts did help 🙂): #41276

@jonahallibone
Copy link

Is there any movement on this by chance? I also manage to kill TS with react-hook-form and recursive type definitions

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Jul 26, 2024
@ilbertt
Copy link

ilbertt commented Aug 8, 2024

I'm facing a similar problem, using react-hook-form's useForm typed with some GraphQL-Codegen's generated mutation input types:

import { useForm } from "react-hook-form";
import { MyMutationInput } from "./graphql/__generated__";

export default function Home() {
  const form = useForm<MyMutationInput>();
  ...

Intellisense stops working and tsc hangs forever during compilation, as soon as I set the type of useForm.

Typescript version: 5.4.5
Platform: MacBook Pro (M3 Pro chip) - macOS Sonoma 14.5

@AlexEscalante
Copy link

AlexEscalante commented Oct 7, 2024

I am facing this issue too with react-hook-form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants