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

Type inference of React component type props is not working correctly #21039

Closed
jchitel opened this issue Jan 5, 2018 · 3 comments
Closed

Type inference of React component type props is not working correctly #21039

jchitel opened this issue Jan 5, 2018 · 3 comments

Comments

@jchitel
Copy link

jchitel commented Jan 5, 2018

TypeScript Version: 2.6.2

Code

function createLazyComponent<P, T extends React.ComponentType<P>>(loader: () => Promise<T>): React.ComponentClass<P> {
	return class extends React.Component<P, { component?: T }> {
		constructor(props: P) {
			super(props);
			this.state = {};
		}

		async componentDidMount() {
			this.setState({ component: await loader() });
		}

		render() {
			const Component = this.state.component as React.ComponentType;
			return Component ? <Component {...this.props} /> : null;
		}
	};
}

const MyComponent = createLazyComponent(async () => (await import('./MyComponent')).default);

Expected behavior:

The code above is for lazy-loading a React component. I would expect the resulting MyComponent to have its props inferred from the props of the component at './MyComponent'.default.

Actual behavior:

The above compiles without errors and will behave as expected, but the props of the resulting component are inferred to {} instead of the actual props. The type parameter T is inferred correctly to the component type in the other module, but the type parameter P is not inferred to the props of T.

I believe it may have something to do with the fact that type parameter P of React.ComponentType<P> has a default value of {}. How do I get it to infer the actual type without having to explicitly specify the parameter?

Additionally, I can't get the first line of render() to work without the cast to React.ComponentType. The next line says that the type T is not callable.

@jchitel
Copy link
Author

jchitel commented Jan 5, 2018

It seems like this may be related to #14729.

@jwbay
Copy link
Contributor

jwbay commented Jan 5, 2018

The only thing that actually needs to be generic is props. Try something like this:

function createLazyComponent<P>(loader: () => Promise<React.ComponentType<P>>): React.ComponentClass<P> {
	return class extends React.Component<P, { component?: React.ComponentType<P> }> {

@jchitel
Copy link
Author

jchitel commented Jan 8, 2018

Sorry for the delay, I was having this issue at work and then the weekend happened, so I had to wait until Monday to try it.

It worked perfectly! Thanks a lot.

@jchitel jchitel closed this as completed Jan 8, 2018
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants