TypeScript 内存泄漏/无限递归,TS挂起,TSC永远不会完成,VSCode和Intellisense死亡,

mzaanser  于 4个月前  发布在  TypeScript
关注(0)|答案(5)|浏览(52)

🔎 搜索词

Typescript挂起,内存泄漏,VS Code,Prisma,React-Hook-Form

🕗 版本与回归信息

  • 这是一次崩溃
  • 我在尝试的每个版本中都遇到了这种行为,并查阅了关于挂起的常见问题解答。
  • 在最新的5.2.2和5.3.0-dev-20231012版本上进行了测试,使用的是typescript@next。

⏯ Playground链接

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

💻 代码

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

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

这会让所有东西都挂起。Typescript不会执行tsc,而智能感知只是一直显示“加载”,无论你悬停在哪里。
与此同时,这个可以正常工作:

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

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

tsc --noEmit --extendedDiagnostics 将在大约3秒内完成。

🙁 实际行为

Typescript无法完成tsc --noEmit,智能感知只是一直显示“加载”,无论你悬停在哪里。我之前遇到过这种情况,只需要将所有设置为any即可。在第一个示例中生成的类型 - 我让它在一个M1 Mac上运行了一个小时59分钟,没有输出。
你可以在codesandbox链接上查看带有最小重现的完整代码示例。它也会在CSB上挂起其智能感知,并且无法执行tsc。
本地和CSB上的CPU都会达到100%。

🙂 预期行为

不挂起typescript,就像你在里面放入任何其他类型一样,例如:

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

gajydyqb1#

我发现提供的代码沙盒很难使用,因为生成的prisma客户端没有包含。我已经提取了生成的客户端并将其放入.app/client中。

另外需要注意的是,这个问题中的仓库描述是不完整的。为了使tsc停滞,需要调用form.register

这里有一个更小的仓库https://github.com/Pyrolistical/typescript-repo-56081

npm run build从未完成。

我开始减少app/client/index.d.ts,但在看到它有多复杂后放弃了。同时,当我减少它时,我注意到tsc确实完成了。因此,极其递归的类型对tsc进程来说真的很难。

ffscu2ro

ffscu2ro2#

谢谢,我能够复现这个问题。它确实看起来像是prisma生成的类型有复杂的模板字符串,所以tscremoveStringLiteralsMatchedByTemplateLiterals和GC上花费了很多时间。我会调查一下是否可以提前切断计算,以及/或者让检查更智能。

mitkmikd

mitkmikd3#

无需库依赖的复现(我认为 react-hook-form 类型可以更简化,但这是我开始调查的好起点)。Prisma生成深度为10+且每个节点分支从0到6+(不是平衡树)的深层嵌套类型。然而,下面的类型大致接近于那个,并且具有相同的性能问题。

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;

一些统计数据(分别针对 Check<t7>Check<t8>Check<t9>):

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

cidc1ykv4#

这个二分法是否终止于$x_{1e0f1}x$?(

$x_{1e1f1}x$也可能有助于检查。)

同样,$x_{1e2f1}x$

46qrfjad

46qrfjad5#

这是引入联合体中的字符串字面量和模板字面量缩减的PR(every-ts确实有所帮助):#41276

相关问题