Skip to content

Type inference in JSX broke in nightly build #27986

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
ulrichb opened this issue Oct 19, 2018 · 6 comments · Fixed by #28002
Closed

Type inference in JSX broke in nightly build #27986

ulrichb opened this issue Oct 19, 2018 · 6 comments · Fixed by #28002
Labels
Bug A bug in TypeScript Domain: JSX/TSX Relates to the JSX parser and emitter Fixed A PR has been merged for this issue

Comments

@ulrichb
Copy link

ulrichb commented Oct 19, 2018

TypeScript Version: 3.2.0-dev.20181019

Search Terms: react jsx type inference

Code

import * as React from "react";

interface ErrorResult {
    readonly error: true
}

interface AsyncLoaderProps<TResult extends {}> {
    readonly asyncLoad: () => Promise<TResult>;
    readonly children: (result: Exclude<TResult, ErrorResult>) => React.ReactChild;
}

class AsyncLoader<TResult extends {}> extends React.Component<AsyncLoaderProps<TResult>> {
    render() { return null; }
}

async function load(): Promise<{ success: true } | ErrorResult> {
    return { success: true };
}

class SomeComponent extends React.Component<{}> {

    render() {
        return (
            <AsyncLoader asyncLoad={load}>{result =>
                <div>{result.success}</div>
            }
            </AsyncLoader>
        );
    }
}

TSC call: npx tsc -t es2017 -m commonjs --jsx react --strict src/TypeScriptIssue.tsx

(Without --strict there is no compile error.)

Expected behavior:
No compile error.

Actual behavior:

src/TypeScriptIssue.tsx:24:26 - error TS2322: Type '() => Promise<ErrorResult | { success: true; }>' is not assignable to type '() => Promise<{ success: true; }>'.
  Type 'Promise<ErrorResult | { success: true; }>' is not assignable to type 'Promise<{ success: true; }>'.
    Type 'ErrorResult | { success: true; }' is not assignable to type '{ success: true; }'.
      Type 'ErrorResult' is not assignable to type '{ success: true; }'.
        Property 'success' is missing in type 'ErrorResult'.

24             <AsyncLoader asyncLoad={load}>{result =>
                            ~~~~~~~~~

  src/TypeScriptIssue.tsx:8:14
    8     readonly asyncLoad: () => Promise<TResult>;
                   ~~~~~~~~~
    The expected type comes from property 'asyncLoad' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<AsyncLoader<{ success: true; }>> & Readonly<{ children?: ReactNode; }> & Readonly<AsyncLoaderProps<{ success: true; }>>'

This is a regression in 3.2.0. Code compiles in 3.1.3.

@DanielRosenwasser
Copy link
Member

Likely a duplicate of #27948

@ulrichb
Copy link
Author

ulrichb commented Oct 19, 2018

@DanielRosenwasser Sure? I've created a a more simple repro.

import * as React from "react";

interface ErrorResult { error: true }

interface AsyncLoaderProps<TResult> {
    readonly prop1: () => Promise<TResult>;

    readonly prop2: (result: Exclude<TResult, ErrorResult>) => any;
    // readonly prop2: (result: TResult) => any; // No error without the `Exclude<>`
}

class AsyncLoader<TResult> extends React.Component<AsyncLoaderProps<TResult>> {
    render() { return null; }
}

async function load(): Promise<{ success: true } | ErrorResult> {
    return { success: true };
}

const loader = <AsyncLoader
    prop1={load}
    prop2={result => result}
/>;

Note that when replacing the Exclude<TResult, ErrorResult> with TResult the code compiles.

So it seems that the parameter type of prop2 somehow influences the inferred TResult (the error message says Type 'Promise<ErrorResult | { success: true; }>' is not assignable to type 'Promise<{ success: true; }>'). But this inference (based on the parameter of prop2 instead of the result type of prop1) simply happens in "the wrong direction". Or what do you think?

@weswigham
Copy link
Member

Likely a duplicate of #27948

:doubt: It's probably not; that only has to do with tags with multiple signatures.

@weswigham weswigham added Bug A bug in TypeScript Fixed A PR has been merged for this issue Domain: JSX/TSX Relates to the JSX parser and emitter labels Oct 19, 2018
@weswigham weswigham added this to the TypeScript 3.2 milestone Oct 19, 2018
@ulrichb
Copy link
Author

ulrichb commented Feb 22, 2019

@weswigham I really don't know why, ... but since updating @types/react (and having a current TS version) the exact same issue appeared again:

image

I've tacked it down and it happened exactly with @types/react@16.7.21 (version @types/react@16.7.20 and before works fine).

I've generated a diff of these two versions: Compare.pdf

And here are the full packages: both_versions.zip

Could you maybe have a look at this?

@weswigham
Copy link
Member

@ulrichb could you open a new issue so it's easier to track?

@ulrichb
Copy link
Author

ulrichb commented Feb 22, 2019

@weswigham Of course. Here it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: JSX/TSX Relates to the JSX parser and emitter Fixed A PR has been merged for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants