Skip to content

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

Description

@DaleR-S

🔎 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

Activity

  1. Pyrolistical commented on Oct 13, 2023

    @Pyrolistical

    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.

  2. PranavSenthilnathan commented on Oct 13, 2023

    @PranavSenthilnathan
    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.

  3. PranavSenthilnathan commented on Oct 16, 2023

    @PranavSenthilnathan
    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
    
  4. jakebailey commented on Oct 20, 2023

    @jakebailey
    Member

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

    also #52345

  5. PranavSenthilnathan commented on Oct 27, 2023

    @PranavSenthilnathan
    Member

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

  6. jonahallibone commented on Jul 22, 2024

    @jonahallibone

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

  7. ilbertt commented on Aug 8, 2024

    @ilbertt

    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

  8. AlexEscalante commented on Oct 7, 2024

    @AlexEscalante

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

  9. nik-webdevelop commented on Mar 28, 2025

    @nik-webdevelop

    Same here: tsc hangs forever, and ide(webstorm) intellisense is stuck in the loading state. After closing an ide, intellisense node.js process remains active

    Update:

    for me, it was failing because of Icon?: FC<SVGProps<SVGElement>>; property

    type Nested = {
      nested: Nested[];
      Icon?: FC<SVGProps<SVGElement>>;
    };
    type FormFields = {
      name: string;
      foo: Nested;
    };
    const { ... } = useForm<FormFields>({ ... });

    if I comment out the Icon property, everything works fine
    ts 5.4.2 react 18.2.0 rhf 7.54.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Needs InvestigationThis issue needs a team member to investigate its status.RescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions