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

Add PropsWithChildren type for components with children #7219

Closed
wants to merge 1 commit into from

Conversation

jonkoops
Copy link
Contributor

Adds a type PropsWithChildren around all components that have children. In React 18 a component type (e.g. FunctionComponent) no longer has an implicit children prop. Adding the PropsWithChildren type restores this behavior.

This is needed to land #7142.

@jonkoops jonkoops mentioned this pull request Apr 12, 2022
20 tasks
@patternfly-build
Copy link
Contributor

patternfly-build commented Apr 12, 2022

@jonkoops jonkoops force-pushed the no-implicit-children branch from a29cbc3 to a6fe62e Compare April 12, 2022 11:26
@jonkoops jonkoops force-pushed the no-implicit-children branch from a6fe62e to 1bca6e2 Compare April 13, 2022 14:37
@jonkoops
Copy link
Contributor Author

jonkoops commented Apr 13, 2022

Can we get some eyes on this? I'll have to keep rebasing and fixing up this PR for most merges upstream.

Note these changes are generated by means of a codemod, so if you'd like to make these changes yourself to verify there are no malicious changes you can run:

npx types-react-codemod implicit-children .
yarn lint packages --fix

Copy link
Contributor

@jenny-s51 jenny-s51 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jonkoops, thank you for these updates!

I'm noticing that for all of the components declared with React.FunctionComponent<React.PropsWithChildren<unknown>>, the react demo for that component doesn't render and displays SyntaxError: Unexpected token. Do you have any idea why this might be happening?

Other demos look great and seem to render fine 👍

@jonkoops
Copy link
Contributor Author

@redallen Perhaps you know how this works? I feel like the TypeScript code is stripped out by theme-patternfly-org somehow, but it trips up when a generic argument is provided?

@nicolethoen
Copy link
Contributor

Unfortunately, redallen is not supporting this project anymore - but maybe we could have @wise-king-sullyman, @jschuler, @jeffpuzzo, or @dgutride take a peek

@wise-king-sullyman
Copy link
Contributor

I don't have extensive knowledge of org, but I can take a look into this today.

A potentially silly question though: since the standard PF pattern is (at least as far as I'm aware) to declare an explicit children prop on the component interface when we have a component take children, is this PR needed?

@jschuler
Copy link
Collaborator

@wise-king-sullyman you raise a good point, how about we just make sure that all components that currently depend on implicit children add children to its props? (if there are any such components)
@jonkoops

@jonkoops
Copy link
Contributor Author

jonkoops commented Apr 19, 2022

Since the standard PF pattern is (at least as far as I'm aware) to declare an explicit children prop on the component interface when we have a component take children, is this PR needed?

@wise-king-sullyman I tried doing an upgrade to the React 18 types and there were quite some places where FunctionComponent was being used without explicitly adding the children prop.

It does look however that this migration is applied everywhere where FunctionComponent is used, even if such a component does not actually expose any children. This is (I assume) to preserve backwards compatibility with existing consumers, as they might be passing children even though nothing happens with them.

@wise-king-sullyman
Copy link
Contributor

This is (I assume) to preserve backwards compatibility with existing consumers, as they might be passing children even though nothing happens with them.

@jonkoops that's true, going the direction of only having children on component interfaces where those children are actually used could be breaking for some consumers. Though as you said it should only be on consumers that are passing children to components that don't take them, so I'm not positive if that would be a blocker or not.

If so it seems like we would need to proceed with this PR, at least until we can do a breaking change.

@jschuler
Copy link
Collaborator

IMO if a consumer uses a component that does not take children, but they still pass them, it's beneficial to "break" them since they might have the wrong assumption that something should be rendered even though it isn't.
@jonkoops do you know if passing empty child would cause an issue? like <Radio isChecked label="Label"></Radio>

@jpuzz0
Copy link
Contributor

jpuzz0 commented Apr 20, 2022

IMO if a consumer uses a component that does not take children, but they still pass them, it's beneficial to "break" them since they might have the wrong assumption that something should be rendered even though it isn't. @jonkoops do you know if passing empty child would cause an issue? like <Radio isChecked label="Label"></Radio>

I agree with @jschuler. It's an opportunity to vet these components and if children are optional or required to specify the children prop explicitly as such. If components allow for children and shouldn't, let's correct those props and remove children.

@jonkoops
Copy link
Contributor Author

do you know if passing empty child would cause an issue? like <Radio isChecked label="Label"></Radio>

This should not result in having any children passed, at least not from a TypeScript perspective. I believe in the case for React it would simply provide undefined as a value, which is expected behavior.

I am a bit hesitant to commit changes that can cause errors in TypeScript, even when the consumer is wrong. For example, I contributed a breaking type change that resulted in (correct) type errors which was reverted (#6766 (comment)).

Personally I agree with @jschuler and @jeffpuzzo but I'd like to have some confirmation before I manually check all of these instances, which is a significant workload.

@tlabaj
Copy link
Contributor

tlabaj commented Apr 22, 2022

IMO if a consumer uses a component that does not take children, but they still pass them, it's beneficial to "break" them since they might have the wrong assumption that something should be rendered even though it isn't. @jonkoops do you know if passing empty child would cause an issue? like <Radio isChecked label="Label"></Radio>

I agree with @jschuler. It's an opportunity to vet these components and if children are optional or required to specify the children prop explicitly as such. If the consumer is passing a components allow for children and shouldn't, let's correct those props and remove children.

I would agree with @jschuler and @jeffpuzzo here.
@jonkoops I understand your hesitation. I do however think this is a little different from your PR we had to revert for Tabs. In the case where a consumer would be passing a children prop that is not explicitly declared, our component would not render it. So technically they are no using the component correctly. I think that might be a good check for the consumer. For the Tabs issue, there was a corner case where it actually did break the api.

We should update any of our components that are not explicitly declaring children that expect the prop. We can open an issue for this and take on the work on our end and split it up with you.

@jonkoops
Copy link
Contributor Author

Awesome, then I think we have reached a conclusion on the approach. I'll go ahead and close this PR so we can instead focus on some smaller PRs that will update the types for individual components where necessary.

@jonkoops jonkoops closed this Apr 26, 2022
@jonkoops jonkoops deleted the no-implicit-children branch April 26, 2022 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants