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

TextControl: support generic props type #64293

Open
wants to merge 10 commits into
base: trunk
Choose a base branch
from

Conversation

meteorlxy
Copy link
Contributor

@meteorlxy meteorlxy commented Aug 6, 2024

What?

Fixes #64292

Why?

It would be helpful to infer the onChange type

How?

  • Making the TextControlProps a generic type
  • Emit event.target.valueAsNumber or event.target.value according to the type of type prop

Testing Instructions

I've added unit tests for type checking.

Testing Instructions for Keyboard

N/A

Screenshots or screencast

Before

image

After

image

@meteorlxy meteorlxy requested a review from ajitbohra as a code owner August 6, 2024 03:24
Copy link

github-actions bot commented Aug 6, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: meteorlxy <meteorlxy@git.wordpress.org>
Co-authored-by: DaniGuardiola <daniguardiola@git.wordpress.org>
Co-authored-by: mirka <0mirka00@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@mirka mirka added [Type] Code Quality Issues or PRs that relate to code quality [Package] Components /packages/components labels Aug 9, 2024
@mirka mirka requested a review from a team August 9, 2024 12:33
@meteorlxy
Copy link
Contributor Author

@mirka I just added type checking in the unit tests following your PR #64069. Maybe you could also help to take a look. Thanks!

Copy link
Contributor

@DaniGuardiola DaniGuardiola left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! Makes sense to me in general, left a few notes.

packages/components/src/text-control/types.ts Show resolved Hide resolved
| 'url';

export type TextControlProps<
Type extends TextControlPropsType = 'text',
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we'll want to use the classic naming strategy for type arguments, and go with T and V for consistency with other instances in the package.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated


export type TextControlProps<
Type extends TextControlPropsType = 'text',
Value extends string | number = Type extends 'number' ? number : string,
Copy link
Contributor

@DaniGuardiola DaniGuardiola Aug 10, 2024

Choose a reason for hiding this comment

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

It might be better to make this a generic type (e.g. ValueFromType<T> and then use it in place of the NoInfer<Value>'s. The value type is not really a type argument, but a computed type from "Type", which is the actual type argument.

This would also allow passing a Type explicitly without the need to pass a Value (there's no partial inference). Why you'd want to do that? I have no idea. But it's possible, so...


Edit: now that I think about it, since it has a default it might work if omitted, but I think the general point still stands


Plus this allows an invalid combination, e.g. type text and value number. It could be fixed by repeating the condition in the extends clause, but I think it's cleaner to just compute it in each prop with a utility generic type as I suggested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

@@ -14,27 +29,17 @@ export type TextControlProps = Pick<
/**
* A function that receives the value of the input.
*/
onChange: ( value: string ) => void;
onChange: ( value: NoInfer< Value > ) => void;
Copy link
Member

Choose a reason for hiding this comment

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

I think this assumption is wrong 🤔 The value that can be retrieved from the change event of an input will always be a string, as far as I can tell. Even if the type is number-like, e.g.number or range. The types for HTMLInputElement confirm this as well.

event.target.value has string type

Copy link
Contributor

Choose a reason for hiding this comment

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

I was wondering about this, actually. I had assumed that maybe React does something special with the number input to make it work directly with numbers, but it seems like that assumption is wrong. Unfortunately, that means the PR does not make sense and should be closed.

Copy link
Contributor Author

@meteorlxy meteorlxy Aug 13, 2024

Choose a reason for hiding this comment

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

Ummm 🤔 Not sure if you have noticed it... (assume that you ignored it?)

In fact it's updated to make use of the valueAsNumber property for type="number":

image

It should work well, and should have great browser support: https://caniuse.com/mdn-api_htmlinputelement_valueasnumber

image

Copy link
Contributor Author

@meteorlxy meteorlxy Aug 13, 2024

Choose a reason for hiding this comment

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

Just added unit tests for this in c2e292a

cc @mirka @DaniGuardiola

Copy link
Member

Choose a reason for hiding this comment

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

Confirming that valueAsNumber browser support is good.

We should still make sure to support a NaN case, as it appears to be a potential return value (see docs):

valueAsNumber
A number that represents the value of the element, interpreted as one of the following, in order: A time value, a number, or NaN if conversion is impossible.

A unit test to cover that scenario would be useful.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, sorry 🤦 But then this is a breaking change, and I don’t think we can ship it on such a widely used and established component, no? I can’t say this is unambiguously a “bug fix” rather than an enhancement.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, this is a big breaking change. I don't think there's nothing to do here unfortunately. At most expose the valueAsNumber attribute and make the generic depend on it. That seems quite convoluted though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Components /packages/components [Type] Code Quality Issues or PRs that relate to code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TextControl: Support generic props type
4 participants