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

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

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 11
  • Comments: 20 (8 by maintainers)

Commits related to this issue

Most upvoted comments

@aleclarson oh! Is anyone else getting what I’m getting the ? Last couple months VSCode as been nearly unusable (with no extensions), autocomplete takes a couple seconds, cursor and text input lags often and sometimes they spike to a freeze. This is on a pretty powerful new laptop.

@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
  }
}

I ran into a similar memory issue which was causing tsc to get killed on CI due to lack of memory. I refactored the code to use the newer React.createRef() API and typed all my refs as RefObject<T>, whose type doesn’t involve { bivarianceHack(instance: T | null): void }["bivarianceHack"] and the memory usage went down enough that my CI build passes again.

I’m posting this here in case this helps someone else who also didn’t want to disable strictFunctionTypes.

Function refs do not have a current property

They don’t define one, however as written a {(instance: T | null): void; readonly current: T | null} would actually be assignable to a { bivarianceHack(instance: T | null): void }["bivarianceHack"], and to a RefObject<T>. However, were the function type defined as type FunctionRef<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"] & { current?: undefined } it would be impossible for a type to be both a RefObject and a RefFunction sans fields of type never, which would themselves imply the containing type can’t actually exist (we don’t currently detect this, which is why it’d also need some changes in TS).

https://github.com/microsoft/TypeScript/pull/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.

is there any other solutions or workarounds for this? for me turning off

"strict": false,
"strictNullChecks": false,
"strictPropertyInitialization": false

fixed it

@weswigham So, you think the best course of action would be to change the Ref type in @types/react?

There’s the trick! Thank you