Skip to content

3.7.2+ Union Type Merged to Single Type in Wrapper #35204

Closed
@RyanLamanskyInsite

Description

@RyanLamanskyInsite

TypeScript Version:
3.8.0-dev.20191119
3.7.2

Search Terms:
Redux
Connect
Union

Code

const mapStateToProps = (state?: {}) => !state ? {} : { foo: 1 };

type Props = ReturnType<typeof mapStateToProps>;

const MyComponent = (props: Props) => null;

// Simplified from react
type FunctionComponent<P> = (props: P & { children: {} }) => null;

// Simplified from react-redux
type Matching<InjectedProps, DecorationTargetProps> = {
    [P in keyof DecorationTargetProps]: P extends keyof InjectedProps
        ? InjectedProps[P] extends DecorationTargetProps[P]
            ? DecorationTargetProps[P]
            : InjectedProps[P]
        : DecorationTargetProps[P];
};

// Simplified from react-redux
type InferableComponentEnhancerWithProps =
    <C extends FunctionComponent<Matching<Props, Props>>>(
        component: C
    ) => never;

(window as any as InferableComponentEnhancerWithProps)(MyComponent);

Expected behavior:
Code should compile without error. This works on 3.6.3 and below.

Actual behavior:

demo.ts:25:56 - error TS2345: Argument of type '(props: { foo?: undefined; } | { foo: number; }) => null' is not assignable to parameter of type 'FunctionComponent<Matching<{ foo?: undefined; } | { foo: number; }, { foo?: undefined; }> | Matching<{ foo?: undefined; } | { foo: number; }, { foo: number; }>>'.
  Types of parameters 'props' and 'props' are incompatible.
    Type '(Matching<{ foo?: undefined; } | { foo: number; }, { foo?: undefined; }> & { children: {}; }) | (Matching<{ foo?: undefined; } | { foo: number; }, { foo: number; }> & { children: {}; })' is not assignable to type '{ foo?: undefined; } | { foo: number; }'.
      Type 'Matching<{ foo?: undefined; } | { foo: number; }, { foo?: undefined; }> & { children: {}; }' is not assignable to type '{ foo?: undefined; } | { foo: number; }'.
        Type 'Matching<{ foo?: undefined; } | { foo: number; }, { foo?: undefined; }> & { children: {}; }' is not assignable to type '{ foo: number; }'.
          Types of property 'foo' are incompatible.
            Type 'number | undefined' is not assignable to type 'number'.
              Type 'undefined' is not assignable to type 'number'.

We encountered this in a very large React/Redux project after attempting to update to 3.7.2.
I simplified the repro case as best I could.
Apologies for the title, I don't know the best terminology for this situation.

Playground Link:
Link
Note that the playground doesn't show a behavior change from 3.7.2 to 3.6.3, but VS Code and the command-line tsc do.

Related Issues:
#33872 - Seems similar and broke at the same time

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions