Repository: TypeScript
Issue: “Type instantiation is excessively deep and possibly infinite” but only in a large codebase
Labels: Bug,Fix Available,Domain: Big Unions,Rescheduled

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Even if you think you've found a *bug*, please read the FAQ first, especially the Common "Bugs" That Aren't Bugs section!

Please help us by doing the following steps before logging an issue:
  * Search: https://github.com/Microsoft/TypeScript/search?type=Issues
  * Read the FAQ: https://github.com/Microsoft/TypeScript/wiki/FAQ

Please fill in the *entire* template below.
-->

<!--
Please try to reproduce the issue with the latest published version. It may have already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly
-->
**TypeScript Version:**  3.7.2, 3.8.0-dev.20191102 (worked in 3.6)

<!-- Search terms you tried before logging this (so others can find this issue more easily) -->
**Search Terms:**

- Type instantiation is excessively deep and possibly infinite.ts(2589)
- Mapped types
- Generics
- Conditional types

**Code**

Note: **this issue manifests itself only in our codebase**. When you run the same code in TypeScript Playground, it seems to be working fine.

The snippet is hardly minimal, but I reduced it as much as I could. I recorded [a video](https://streamable.com/pjkrk) where exactly the same code yields an error different than the one in TypeScript Playground. I tried with two versions of TypeScript: `3.7.2` and `3.8.0-dev.20191102`. It worked correctly with `3.6`.

Since @sheetalkamat and @DanielRosenwasser have access to our repository, you're welcome to have a look at [this PR](https://github.com/unsplash/unsplash-web/pull/4243). Copy-paste the code below anywhere in the project to see the error.

The versions of types used:

- `@types/history@4.7.3`
- `@types/react@16.9.11`
- `@types/react-router-dom@5.1.0`
- `@types/recompose@0.30.7`

**Note**: Interestingly enough, if you change:

```diff
- declare const Button: React.FunctionComponent<Omit<Props, never>>;
+ declare const Button: React.FunctionComponent<Props>;
```

it works again despite the fact `Omit<Props, never>` should be the same as just `Props`.

<details>

<summary>Source code</summary>

```ts
import { History } from 'history'; // "4.7.3"
import * as React from 'react'; // "16.9.11"
import { LinkProps, RouteComponentProps, withRouter } from 'react-router-dom'; // "5.1.0"
import { getDisplayName } from 'recompose'; // "0.30.7"

declare function isDefined<T>(candidate: T | null | undefined): candidate is T;
declare function isString(value?: any): value is string;

type ObjectOmit<T extends K, K> = Omit<T, keyof K>;

type OnClick = NonNullable<React.ComponentProps<'button'>['onClick']>;

type OnClickProp = {
  /** If there is a custom click handler, we must preserve it. */
  onClick?: OnClick;
};

type ProvidedProps = OnClickProp;

type InputProps = OnClickProp & {
  /** Note: we want this helper to work with all sorts of modals, not just those backed by query
   * parameters (e.g. `/photo/:id/info`), which is why this must accept a full location instead of a
   * `Modal` type.
   * */
  to: Exclude<LinkProps['to'], Function>;
};

const buildClickHandler = ({
  to,
  onClick,
  history,
}: InputProps & {
  history: History;
}): OnClick => {
  const navigate = () => {
    // https://github.com/Microsoft/TypeScript/issues/14107
    isString(to) ? history.push(to) : history.push(to);
  };

  return event => {
    [onClick, navigate].filter(isDefined).forEach(callback => callback(event));
  };
};

/** See the test for an example of usage. */
export const enhance = <ComposedProps extends ProvidedProps>(
  ComposedComponent: React.ComponentType<ComposedProps>,
) => {
  type PassThroughComposedProps = ObjectOmit<ComposedProps, ProvidedProps>;
  type OwnProps = InputProps & RouteComponentProps<never> & PassThroughComposedProps;
  type Props = OwnProps;

  const displayName = `CreateModalLink(${getDisplayName(ComposedComponent)})`;

  const ModalLink: React.FunctionComponent<Props> = ({
    to,
    onClick,

    history,
    // We specify these just to omit them from rest props below
    location,
    match,
    staticContext,

    ...passThroughComposedProps
  }) => {
    const clickHandler = buildClickHandler({ to, onClick, history });

    const composedProps: ComposedProps = {
      // Note: this is technically unsafe, since the composed component may have props
      // with names matching the ones we're omitting.
      // https://github.com/microsoft/TypeScript/issues/28884#issuecomment-503540848
      ...((passThroughComposedProps as unknown) as PassThroughComposedProps),
      onClick: clickHandler,
    } as ComposedProps;

    return <ComposedComponent {...composedProps} />;
  };

  ModalLink.displayName = displayName;

  return withRouter(ModalLink);
};

type Props = React.ComponentPropsWithoutRef<'button'> &
  Required<Pick<React.ComponentPropsWithoutRef<'button'>, 'type'>>;

/**
 * This one errors.
 */
declare const Button: React.FunctionComponent<Omit<Props, never>>;

/**
 * This one works.
 */
// declare const Button: React.FunctionComponent<Props>;

const EnhancedButton = enhance(Button);

/**
 * Type instantiation is excessively deep and possibly infinite.ts(2589).
 */
() => <EnhancedButton></EnhancedButton>;


```

</details>

**Expected behavior:**

I should get a proper error about missing properties (not the one about type instantiation):

```
Type '{}' is missing the following properties from type 'Readonly<Pick<OwnProps, "form" | "style" | "title" | "onClick" | "to" | "key" | "autoFocus" | "disabled" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | ... 252 more ... | "onTransitionEndCapture">>': to, type(2739)
```

**Actual behavior:**

I'm getting this:

```
Type instantiation is excessively deep and possibly infinite.ts(2589).
```

**Playground Link:** <!-- A link to a TypeScript Playground "Share" link which demonstrates this behavior -->

[Playground Link](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAbzgCWAZxtAnnAvnAMyghDgHIALdTKLMgbgChRJY4AqOAQzTgCUAplwDG8IiXJQhohs3DR4SADLAAdgGsACsTBoANPwgBXGAIDCJSKoGqY2iLoMB3YDAp9jpqHkLFSZKREYAFpiEwEoYIATElkWBUQ4AHMBGAARdDAAGy4sADkuEAEfcX8pYUsINAFZRiiBYRypQiNVUWAIVTh0NIECNQEogB4AFQA+AAphLlUo4CiuUwAuOBG4AB84VSMsrI24Vvr+6yiAShXp2fnF4vRVpnrGrmaCVvbO7rQAZRgoNSSJgA3LhZIwCAD8KxmWHOcGBoNuvAwf1USSYjBgWDAxQA8gAjABWDRgOJArlGcAEAA9TLNeABpAz0sZwAC8cFJ5JGBnUAiwEAIcGZ6Mx2I5qjMWWAwnUbLgeU6eR2OTxWQEQ0EQQAdBZ5NZbPZdEMyHiTJhVGQxgBtMidSXS9RkAC6YxFWNxEqlMsNcoQjDgcAA9OxOABJQVuCKI7hwYRGDASRoOuAUGZRNVQZzFEDx+BgKTVKCA24wLUcQP+uB2r3qSHi+0ypi4N1i+yA+aDQ28dk4z0Ow0t4qh1RgExduW9htaHRwABkiErwc4CuWcCcxScM3gbjuFAEWWx3kwa+gspcbm4uzgaAUvAFcBAEAWWX0Wwg8AJubgbiqxTxIl5KI4DxHAAEcwVoSsODgMBnkKVIIl4CYBC1JIywAA0DMAKHfCBAyWeZAzUAgIHQ05nCoYQKE+NcKBwHdeBzDBuGEYQBDAeAuBaK8sggaYYA6Lo1AwIQgPvLgoM4dCAFknxBdDv3dLVJPLStMBWABRKlGiMeohhUDQuxtTBnQMAAxN4BM6V1GGbRhGAqVRmNNYAsiiKdkDTDM5QmP0A0wPRK2rB1AoDKgE1oQLcBWYdRzsHReHnPyU2obAVlQCKsCbWFJxrNkWWSxzmNULh2ySG4fNOfKFwDANA0DFMYBgXQlnqpJXAoIw8S1CoQEDaTpWIG8CBgQMRndL5hD+DiiLQNAwTQQMAEYABYloABgAdigz4fhRAFMCq8EUsyrVRzQCgJkOuAVnCmgsDO+NLsOpgAzsyspBgIwoC6ARi1sarkoDK1gplAwSrKm4nS1fosi8CYej6AYzhh6ANJES7pl2f8ZWqrGshx9RkP+mBTlOV68CbdElzgL4BGKSNvwEZiSO8GZKSpQpsmKe94y4FIy3YCtqVYeAivgGxUzaYp2SGXVIGqKJx2pWkol4NsOyVhLJkreXf3cyp9RgFZNVEHVDZsGBxuxOXKkVrsxkCqrWQKtT3TgTQeDQEYKDCJIKD1+2EonQliU5GBbfkIOHFfDX6i1mObP892cScVRx3ZWKx2D+cPHCPWja7IZrGLKAWXnT25p9v2A7tzsEop0Vigzjk067dEA3FuA5jQbJcgKIo5XQsxAlMWTnwMomABIEBSdJMhyfJ4ImQPBgLy3TlwU50I72NOmY8eQUnk3pFLCy2isiULdsIYHZ8oHvwgULatB9RAp2u7sGfuqGoAdWKXuDRgAEHonuaocBPzMWPCQVw349ykFKHAAseZg54n3BAJwO1eL8UEt-B8iwqJ4IwIsaUFhbAq3frVOAWoaGwSrr7Yw-tV4J10JWLegMdpdyTDKTysxvLshcm5DyXkIi+UfgYV+BhP60DwOTeyVCuF1xYWgFYzCW4Px-vKd8AgVgMRoqYKiqhpQgiyDgVoaAuAEAEAYNAag2JwOKL1BWgw956ktvgnAqZiwwQSjtTR55qIlSKIxAhVBUQOKrNYXg64Ag8zJE1f4ykqGaIoE1FqbUOpdR6iQQMZIppVAFKNa2AhJrTVGugeazNAwACYAAc9SVoAGIKlgl6kUWwwQACs60ADMnSVrrVqStWpfjqE0ImBMOh3sGFGCYUo8cPADgaFUBg1QVVFmV2mTXNRCVyKjNfhcGsvD0wRDwfgRZOyY67wDJ9b6XRI7OINm4gGCAaHZKjvXGO+BAxJ0pvIuAh8siTy1D3PuS9B7slBYvAeAhd63J+muDqed4aAsnnI96TcPbB3ZKbUs68DQJV-h1TwggCDGlNE1Tolo5yVkEOBYAUhhiaAdBqU+5tnnxRjkSn8JhSXkrNFSx25Am6WhsowJc-pOA+zuJ0YoERiBQDQEkoWdQGhNEcfveAAAhAVqgT7anPu8K+HKhjh1vglcGf0IhjDFRK6C0q7zWBPFAdQSrJUVnqt3NVzwNVOW1bq-VZtDWX3xRHB26Iu4aVUFLNiUQdWUq6OySWMw2ITHjeaOR4qQyStWO7YSMAtzABIR8O41I2JzWAMWUxXr2LcFmDBKotjVQ4GImoVwKEYBoAmNUzptSACcpxlUVgmM7FkQwo0xsGOm6yQxAwTpTVO3VYqgA)

**Related Issues:** <!-- Did you find other bugs that looked similar? -->

- #32735
- #34850