Skip to content
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

5.0: Narrowing from type-guards ignored when constructing JSX call (2604) #53178

Closed
eps1lon opened this issue Mar 9, 2023 · 12 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@eps1lon
Copy link
Contributor

eps1lon commented Mar 9, 2023

Bug Report

🔎 Search Terms

does not have any construct or call signatures.(2604)

🕗 Version & Regression Information

  • This changed between versions 4.9.5 and 5.0.1-rc (I'm pretty sure it used to work in 5.0.0-beta but can't verify with playground)

⏯ Playground Link

Playground link with relevant code

💻 Code

We saw 8 errors in our codebase pop up. This might be a fairly common issue in React Native codebases or any codebase having types like React.ComponentType<any> | React.ReactElement.

import * as React from 'react'

// `@types/react-native` FlatListProps['ListHeaderComponent']
declare const ListHeaderComponent: React.ComponentType<any> | React.ReactElement

// JSX element type 'ListHeaderComponent' does not have any construct or call signatures.(2604)
const elementB = React.isValidElement(ListHeaderComponent) ? ListHeaderComponent : <ListHeaderComponent />

Note that this works either with either

-declare const ListHeaderComponent: React.ComponentType<any> | React.ReactElement
+declare const ListHeaderComponent: React.ComponentType<any> | React.ReactElement<unknown>

which requires a change in @types/react-native

or

-declare function isValidElement(maybeElement: unknown): maybeElement is React.ReactElement<unknown>
+declare function isValidElement(maybeElement: unknown): maybeElement is React.ReactElement<any>

which requires a change in @types/react.

The change in @types/react-native makes more sense but means other type libraries need to update as well.

3rd option is making React.ReactElement default to React.ReactElement<unkown> instead of React.ReactElement<any> but that might be even more disruptive.

I'll fiddle with each alternative but I would appreciate if you could check if this new behavior in TypeScript is so valueable to warrant this breakage in the ecosystem.

🙁 Actual behavior

JSX element type 'ListHeaderComponent' does not have any construct or call signatures.(2604)

🙂 Expected behavior

No type error since isValidElement narrows to React.ReactElement i.e. the else branch should just be React.ComponentType<any>

@RyanCavanaugh
Copy link
Member

Duplicate #52232

@eps1lon
Copy link
Contributor Author

eps1lon commented Mar 10, 2023

The linked issue repros in 4.9.4 while mine does not. Could you clarify why you think it is a duplicate?

@RyanCavanaugh
Copy link
Member

I believe the root cause here - isValidElement and ReactElement having different default type arguments, thus resulting in subtyping assymmetry, is still the same. If you have a repro that doesn't depend on React we can bisect it and verify.

@eps1lon
Copy link
Contributor Author

eps1lon commented Mar 11, 2023

So if it turns out to root cause is a dupe, you won't consider this a 5.0 regression even though it only started failing when going from 4.9 to 5.0?

@eps1lon
Copy link
Contributor Author

eps1lon commented Mar 11, 2023

@Andarist
Copy link
Contributor

Bisected to #52282

fwouts added a commit to fwouts/previewjs that referenced this issue Mar 20, 2023
JSX function signatures are now detected as `any` in some projects such as https://github.com/alveshelio/solidjs-previewjs.

This looks like it could be related to microsoft/TypeScript#53178
@RyanCavanaugh
Copy link
Member

Right, this is basically the converse report of #50916

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Mar 30, 2023
@eps1lon
Copy link
Contributor Author

eps1lon commented Mar 30, 2023

I'm not following the labelling here. It's considered a duplicate of an issue that was closed by the PR that caused it? Sounds more like you're saying this is intended behavior?

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@greypants
Copy link

I'm also having a hard time trying to follow the thread here... I still have this issue on 5.0.3. Are we waiting on a change in @types/react then? Or is this supposed to be fixed already?

@noahtallen
Copy link

noahtallen commented Jul 31, 2023

This issue unfortunately isn't fixed! I'm still getting errors in Typescript 5.1.6. (I'm pretty sure this is the same issue.)

Here is a playground showing the error. The problem is that object is ReactElement<Props> does not work to narrow the types, but object is ReactElement does work.

@Andarist
Copy link
Contributor

Andarist commented Aug 1, 2023

Just a note: it works when u "forward" the P TS playground:

type Foo = {
	bar: string;
}

// Stub of ReactElement:
interface ReactElement<P = any> {
	props: P;
}

declare function isValidElement<P>(object: {} | null | undefined): object is ReactElement<P>

function doSomething<P>(input: Foo | ReactElement<P>) {
	if (isValidElement(input)) {
		return input;
	}
	// Type should be narrowed, and it is
	return input.bar;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

6 participants