Skip to content

JSDocs @typedef parsing runs into infinite loop #40234

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

Closed
clshortfuse opened this issue Aug 25, 2020 · 3 comments · Fixed by #40861
Closed

JSDocs @typedef parsing runs into infinite loop #40234

clshortfuse opened this issue Aug 25, 2020 · 3 comments · Fixed by #40861
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@clshortfuse
Copy link

TypeScript Version: v4.1.0-dev.20200824

Search Terms:

Code

TS:

export type XMLObject<T> = {
  $A: {
    [K in keyof T]?: XMLObject<T[K]>[]
  },
  $O: {
    [K in keyof T]?: {
      $$?: Record<string, string>
    } & (T[K] extends string ? {$:string} : XMLObject<T[K]>)
  },
  $$?: Record<string, string>,
  } & {
  [K in keyof T]?: (
    T[K] extends string ? string
      : XMLObject<T[K]>
  )
};

const p:XMLObject<{foo:string}> = {};

JS:

/**
 * @template T
 * @typedef {{
  $A: {
    [K in keyof T]?: XMLObject<T[K]>[]
  },
  $O: {
    [K in keyof T]?: {
      $$?: Record<string, string>
    } & (T[K] extends string ? {$:string} : XMLObject<T[K]>)
  },
  $$?: Record<string, string>,
  } & {
  [K in keyof T]?: (
    T[K] extends string ? string
      : XMLObject<T[K]>
  )
}} XMLObject<T> */

/** @type {XMLObject<{foo:string}>} */
const p = {};

Expected behavior:

VSCode Intellisense outputs should match and results should somewhat as fast in JS as in TS.

Actual behavior:

Extremely long parsing time, Intellisense mismatch and long, infinitely looping type details. Hovering over XMLObject in the playground link takes a very long time on JS.

JS: loop example

TS:
loop example2

Playground Link:

JS: https://www.typescriptlang.org/play?ts=4.1.0-dev.20200824&useJavaScript=true#code/PQKhCgAIUgBAXApgWwA4BsCGTIBUowICeqiAJogGaQDeNUkAJAIIBctDkkA2gNKQBLAHaQA1oiIB7argC6AfnYANALIAZAPIAjAFaIAxvAA8uPrIB83WQwC+AGgaMN7ely59BI8VJkKXnN0ZGRUgAJQNJACcyIwBneEjhAHM7SHjEoSTzAJtIADJIAApTXllIRAAPJCEyWLSE5Mh5WkZWdOTc5XVtPUMTM3MASlsHLiCQ8P0omPbM1Nms0chcgtcefmExCWk8PyKAkrLK6tr6jKSms+SAri7NXQNjQ+yuYZtc1Xvep-NoYHBwKBCPASIhaJ8eo8jDRKJJJG0GpkbOZciB-lMhPFIKhIABeWg2ADc4CAA

TS: https://www.typescriptlang.org/play?ts=4.1.0-dev.20200824#code/KYDwDg9gTgLgBDAnmYcAaBZAMgeQEYBWwAxjADwAqAfHALxwDeAUHHACQCCAXIy63AG0A0nACWAOzgBrYIggAzOBQC6Afh6ZchEuQrDlVAcr4BfADR82OHs36CRE6bIVK1NvnbZt1cAEoloABMyAGcYKAkAczM4MIjxSKoPOBM4ADI4AAo9IWU4UBhgcUCQ2PCouFVGNi44qNSNbHwiUkp9KgBKUwtWLx9-YiDQ8oSYuoSqHpT03lZhMUkZOUUVH0zknLyCopKy+MjKvajk1katFt12vi6TAG4mJkHxMLgwLk1mnTIGeQgIWpGkRMNHoDDuTCAA

Related Issues:

@clshortfuse
Copy link
Author

clshortfuse commented Aug 25, 2020

I see what's going on. The JSDocs parser is including $A and $O as part of T when it runs the last [K in keyof T].

I can work around the issue by breaking apart the first part into its own type first.

export type XMLObjectBase<T> = {
  $A: {
    [P in keyof T]?: XMLObject<T[P]>[]
  },
  $O: {
    [P in keyof T]?: {
      $$?: Record<string, string>
    } & (T[P] extends string ? {$:string} : XMLObject<T[P]>)
  },
  $$?: Record<string, string>,
};

export type XMLObject<T> = XMLObjectBase<T> & {
  [K in keyof T]?: (T[K] extends string ? string : XMLObject<T[K]>)
};

The parser is probably compiling a type as one big one on the fly and getting stuck in an infinite loop.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Aug 25, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.1.0 milestone Aug 25, 2020
@RyanCavanaugh RyanCavanaugh added Rescheduled This issue was previously scheduled to an earlier milestone and removed Rescheduled This issue was previously scheduled to an earlier milestone labels Aug 31, 2020
@sandersn
Copy link
Member

I thought this might be the result of changing ? to parse as a type postfix only when no other interpretation is possible, but the bad behaviour repros on 3.9 and 4.0 too.

@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Sep 30, 2020
@sandersn
Copy link
Member

The code that makes recursive type aliases work failed on typedefs. #40861 fixes this.

sandersn added a commit that referenced this issue Sep 30, 2020
sandersn added a commit that referenced this issue Oct 2, 2020
* Fix reference types in @typedef

Previously this code path was broken and untested. Fortunately the fix
is simple.

* add test case from #40234

* update baselines
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants