Skip to content

tsc, tsserver: hangs with large union type and object spread in React HOC (strict mode) #29949

Description

@jgoz

TypeScript Version: 3.4.0-dev.20190216

Search Terms: hang higher order union strictFunctionTypes

Code

Note that this code has compilation errors, but that's not important. When invoking tsc or loading in an editor that uses tsserver, the compilation hangs/never completes.

import * as React from "react";

const animated: {
  [Tag in keyof JSX.IntrinsicElements]: React.ForwardRefExoticComponent<
    React.ComponentPropsWithRef<Tag>
  >
} = {};

function makeAnimated<T extends React.ReactType>(
  comp: T
): React.ForwardRefExoticComponent<React.ComponentPropsWithRef<T>> {
  return null as any; // not important
}

export interface UpgradedProps {
  show: boolean;
}

export function test<P>(
  component: React.ComponentType<P> | keyof React.ReactHTML
): React.ComponentType<P & UpgradedProps> {
  // changing to `const Comp: any` un-hangs tsserver
  const Comp =
    typeof component === "string"
      ? animated[component]
      : makeAnimated(component);

  return React.forwardRef<any, P & UpgradeProps>((props, ref) => {
    const { show, ...ownProps } = props; // addition of this line causes the hang
    return show ? <Comp {...ownProps} ref={ref} /> : null;
  });
}

Expected behavior:

Compilation completes (optionally with errors).

Actual behavior:

Compilation hangs.

Repro Link: https://github.com/jgoz/typescript-bug

Related Issues: Didn't find anything recent

Activity

  1. changed the title [-]tsc, tsserver: hangs with large union type in React HOC[/-] [+]tsc, tsserver: hangs with large union type and object spread in React HOC[/+] on Feb 18, 2019
  2. RyanCavanaugh commented on Feb 27, 2019

    @RyanCavanaugh
    Member

    With Version 3.4.0-dev.20190227:

    D:\Throwaway\reactish>tsc a.tsx --diagnostics
    a.tsx:3:7 - error TS2740: Type '{}' is missing the following properties from type '{ a: ForwardRefExoticComponent<Pick<DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "media" | "hidden" | "dir" | "slot" | "style" | "title" | "color" | "key" | "children" | ... 249 more ... | "onTransitionEndCapture"> & { ...; }>; ... 170 more ...; view: ForwardRefExoticComponent<...>; }': a, abbr, address, area, and 168 more.
    
    3 const animated: {
            ~~~~~~~~
    
    a.tsx:28:3 - error TS2322: Type 'ForwardRefExoticComponent<Pick<any, string | number | symbol> & RefAttributes<any>>' is not assignable to type 'ComponentType<P & UpgradedProps>'.
      Type 'ForwardRefExoticComponent<Pick<any, string | number | symbol> & RefAttributes<any>>' is not assignable to type 'FunctionComponent<P & UpgradedProps>'.
        Types of property 'defaultProps' are incompatible.
          Type 'Partial<Pick<any, string | number | symbol> & RefAttributes<any>>' has no properties in common with type 'Partial<P & UpgradedProps>'.
    
    28   return React.forwardRef<any, P & UpgradeProps>((props, ref) => {
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    29     const { show, ...ownProps } = props; // addition of this line causes the hang
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    30     return show ? <Comp {...ownProps} ref={ref} /> : null;
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    31   });
       ~~~~~
    
    a.tsx:28:36 - error TS2304: Cannot find name 'UpgradeProps'.
    
    28   return React.forwardRef<any, P & UpgradeProps>((props, ref) => {
                                          ~~~~~~~~~~~~
    
    a.tsx:30:19 - error TS17004: Cannot use JSX unless the '--jsx' flag is provided.
    
    30     return show ? <Comp {...ownProps} ref={ref} /> : null;
                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    
    Found 4 errors.
    
    Files:            13
    Lines:         65254
    Nodes:        211336
    Identifiers:   67355
    Symbols:      148609
    Types:         58118
    Memory used: 174251K
    I/O read:      0.02s
    I/O write:     0.00s
    Parse time:    0.50s
    Bind time:     0.22s
    Check time:    3.50s
    Emit time:     0.03s
    Total time:    4.25s
    

    With --skipLibCheck (highly recommended), total time is 1.44s. Can you try with latest and see what you see?

  3. jgoz commented on Feb 27, 2019

    @jgoz
    Author

    Ryan Cavanaugh (@RyanCavanaugh) With Version 3.4.0-dev.20190227, tsc does complete but tsserver still hangs. This can be observed in VS Code by hovering the mouse over animated or makeAnimated - it just shows Loading... and never changes.

    I do have "skipLibCheck": true in my tsconfig.

    I tweaked the example to remove compilation errors:

    import * as React from "react";
    
    const animated: {
      [Tag in keyof JSX.IntrinsicElements]: React.ForwardRefExoticComponent<
        React.ComponentPropsWithRef<Tag>
      >
    } = {} as any;
    
    function makeAnimated<T extends React.ReactType>(
      _comp: T
    ): React.ForwardRefExoticComponent<React.ComponentPropsWithRef<T>> {
      return null as any; // not important
    }
    
    export interface UpgradedProps {
      show: boolean;
    }
    
    export function test<P>(
      component: React.ComponentType<P> | keyof React.ReactHTML
    ): any {
      // --> changing to `const Comp: any` un-hangs tsserver <--
      const Comp =
        typeof component === "string"
          ? animated[component]
          : makeAnimated(component);
    
      return React.forwardRef<any, P & UpgradedProps>((props, ref) => {
        const { show, ...ownProps } = props;
        return show ? <Comp {...ownProps} ref={ref} /> : null;
      });
    }
  4. RyanCavanaugh commented on Feb 27, 2019

    @RyanCavanaugh
    Member

    image

    Not sure what's going on! If you can get a debugger attached to tsserver that may be helpful, though it's hard to say since this is a pretty small repro and we really should be seeing the same results.

  5. jgoz commented on Feb 27, 2019

    @jgoz
    Author

    Here is my tsconfig for reference:

    {
      "compileOnSave": false,
      "compilerOptions": {
        "importHelpers": true,
        "jsx": "react",
        "lib": [
          "dom",
          "es5",
          "es2015.collection",
          "es2015.iterable",
          "es2015.promise",
          "es2015.symbol"
        ],
        "module": "commonjs",
        "moduleResolution": "node",
        "noImplicitReturns": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "preserveConstEnums": true,
        "preserveSymlinks": true,
        "removeComments": false,
        "skipLibCheck": true,
        "sourceMap": true,
        "strict": true,
        "target": "es5"
      }
    }
  6. jgoz commented on Feb 27, 2019

    @jgoz
    Author

    Ryan Cavanaugh (@RyanCavanaugh) I just disabled all options and re-enabled one-by-one. The server will hang when strict: true is set.

    {
      "compileOnSave": false,
      "compilerOptions": {
        "jsx": "react",
        "skipLibCheck": true,
        "strict": true
      }
    }
  7. RyanCavanaugh commented on Feb 27, 2019

    @RyanCavanaugh
    Member

    There's the trick! Thank you

  8. changed the title [-]tsc, tsserver: hangs with large union type and object spread in React HOC[/-] [+]tsc, tsserver: hangs with large union type and object spread in React HOC (strict mode)[/+] on Feb 27, 2019
  9. sheetalkamat commented on Feb 27, 2019

    @sheetalkamat
    Member

    Pretty sure this is to do with type string genaration.

  10. 44 remaining items

  11. weswigham commented on Feb 27, 2023

    @weswigham
    Member

    #42772 may still be valuable enough to revive at some point if operating close to our limits is truly common, but we've already done a lot of recentish work to defer/simplify unions like these wherever possible, and minimally, we should issue a complexity error rather than hang nowadays.

  12. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptDomain: check: Big UnionsThe root cause is ultimately that big unions interact poorly with complex structuresRescheduledThis 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