-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Add ComponentProps reference as first React Types example #626
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
--- | ||
title: ComponentProps<ElementType> | ||
--- | ||
|
||
`ComponentProps<ElementType>` constructs a type with all valid props of an element or inferred props of a component. | ||
|
||
:::note | ||
|
||
Prefer `ComponentPropsWithRef<ElementType>` if ref is forwarded and `ComponentPropsWithoutRef<ElementType>` when ref is not forwarded. | ||
|
||
::: | ||
|
||
## Parameters | ||
|
||
- `ElementType`: An element type. Examples include: | ||
- An HTML or SVG element string literal such as `"div"`, `"h1"` or `"path"`. | ||
- A component type, such as `typeof Component`. | ||
|
||
## Usage | ||
|
||
### Get all valid props of an element | ||
|
||
`ComponentProps<ElementType>` can be used to create a type that includes all valid `div` props. | ||
|
||
```tsx | ||
interface Props extends ComponentProps<"div"> { | ||
text: string; | ||
} | ||
|
||
function Component({ className, children, text, ...props }: Props) { | ||
// `props` includes `text` in addition to all valid `div` props | ||
} | ||
``` | ||
|
||
### Infer component props type | ||
|
||
In some cases, you might want to infer the type of a component's props. | ||
|
||
```tsx | ||
interface Props { | ||
text: string; | ||
} | ||
|
||
function Component(props: Props) { | ||
// ... | ||
} | ||
|
||
type MyType = ComponentProps<typeof Component>; | ||
// ^? type MyType = Props | ||
``` | ||
|
||
#### Infer specific prop type | ||
|
||
The type of a specific prop can also be inferred this way. Let's say you are using an `<Icon>` component from a component library. The component takes a `name` prop that determines what icon is shown. You need to use the type of `name` in your app, but it's not made available by the library. You could create a custom type: | ||
|
||
```tsx | ||
type IconName = "warning" | "checkmark"; | ||
``` | ||
|
||
However, this type if not really reflecting the actual set of icons made available by the library. A better solution is to infer the type: | ||
|
||
```tsx | ||
import { Icon } from "component-library"; | ||
|
||
type IconName = ComponentProps<typeof Icon>["name"]; | ||
// ^? type IconName = "warning" | "checkmark" | ||
``` | ||
|
||
You can also use the `Pick<Type, Keys>` utility type to accomplish the same thing: | ||
|
||
```tsx | ||
import { Icon } from "component-library"; | ||
|
||
type IconName = Pick<ComponentProps<typeof Icon>, "name">; | ||
// ^? type IconName = "warning" | "checkmark" | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
title: React Types | ||
--- | ||
|
||
`@types/react` makes some types available that can be very useful. Here's a list in alphabetical order with links to the detailed reference pages. | ||
|
||
- [`ComponentProps<ElementType>`](/docs/react-types/ComponentProps) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally always found that confusing. The whole point of
ComponentProps
is to get the props but at the same time I should know that it has aref
? Or does that meanComponentPropsWithoutRef
is just a shorthand forOmit<ComponentPropsWithRef<T>, 'ref'>
?Either way, this confusion already exist in the types so I'd hope we can do a follow-up with either clearer instructions or a plan to only
ComponentProps
and deprecate/remove the ones related toref
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I tend to use
ComponentProps
despite the recommendation to prefer "being explicit about the ref", and I have never had problems with it.I made a small experiment and found that
ComponentProps
probably is a better default when passing a component type, because it correctly infers whether or not ref is forwarded.TypeScript playground
Is there a case for being explicit when passing an element string literal? Is
ComponentPropsWithRef<"div">
even something you'd want to do?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer having a single
ComponentProps
if the only justification forComponentPropsWithoutRef
is a shorthand forComponentProps
+Omit
.Long-term we won't have
forwardRef
anyway and thenref
will be in the props interface for function components.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any insights into how you'll define
ref
s in the future? Just a regular prop like this?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to investigate if we can deprecate
ComponentPropsWithRef
andComponentPropsWithoutRef
in @types/react. Any tips on how to go about it? Make a PR with these thoughts? Someone in particular to get in touch with before taking that step?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd try to find out when they got introduced and why. Then deprecate and provide a counter argument to the initial rationale. By default we don't want to add stuff unless we have to. And if it is convenience there needs to be frequent usage.