Improve ButtonWithMenu types, add tests for Button types #49585
Merged
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.
I was working on a component that was using
ButtonWithMenu
. I noticed that I was able to pass anonClick
function to it that had a signature which didn't match what's expected from a regularonClick
.This was the case because of the type used to describe the rest of the props:
[buttonBorderProp: string]: any
. This makes it so thatButtonWithMenu
accepts any kind of prop and its type doesn't matter.I made an attempt to fix that by replacing this with
props: { <known props> } & ButtonProps<'button'>
. This seemed to work well until I found a callsite which uses theforwardedAs
prop:teleport/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx
Lines 207 to 217 in 76bfe76
The type that I came up with didn't want to allow the
target
andhref
props because they don't exist on<button>
. So I needed to somehow make TS treatButtonWithMenu
asa
whenforwardedAs
is passed.After wrestling with the types for an hour, I wrote a simple test which serves two purposes. First, it checks if wrong props are rejected by TS. Second, it checks if the component under tests actually renders as
<button>
or<a>
. This test case reproduces the problem that I ran into inButtonWithMenu
.I found that depending on whether
forwardedAs
oras
is needed, I need to use eitherComponentPropsWithoutRef
orComponentPropsWithRef
– I can't quite explain why it's the case, but this works for now and the test passes.As for
forwardedAs
vsas
, I believeforwardedAs
is needed because when thecss
prop is used, it creates a wrapper component around the original styled component.The third idea behind the test is to make it serve as a template whenever someone needs to provide a type for rest props. There's a bunch of other places with types for rest props (see
rg "\[.*\]: any"
) which could use such change in the future.