downshift icon indicating copy to clipboard operation
downshift copied to clipboard

getInputProps return type gives an opinion on props that it doesn't actually return

Open MarkFalconbridge opened this issue 4 years ago • 4 comments

  • downshift version: 6.0.5
  • node version:
  • npm (or yarn) version:

Relevant code or config

export interface GetInputPropsOptions
  extends React.HTMLProps<HTMLInputElement> {
  disabled?: boolean
}

What you did: Created a component to use as an input which wraps <input> and used Typescript to narrow down a member of its props interface that Downshift doesn't care about and then tried to apply the result of getInputProps to it.

What happened:

Typescript warns me that the types don't match.

Reproduction repository:

See line 44 here - https://codesandbox.io/s/priceless-waterfall-sj86t?file=/src/downshift/ordered-examples/00-get-root-props-example.tsx (it's a modified version of the standard Downshift examples to illustrate the issue)

Problem description: The interface that getInputProps is declared as returning extends React.HTMLProps<HTMLInputElement> even though it returns only a tiny proportion of that interface. Because it extends React.HTMLProps<HTMLInputElement> it is giving an opinion on the shape of props that it doesn't actually care about.

Suggested solution: Narrow down the return type of getInputProps to match the props it actually returns.

MarkFalconbridge avatar Feb 05 '21 11:02 MarkFalconbridge

Narrow it down to what? You should be able to pass anything input related to getInputProps, and it should return those same attributes on that input element, along with the downshift defaults that are also input-related. Yes, we only return only some input attributes but also ....rest so the resulted return type is Input props. I don't see the problem here.

silviuaavram avatar Feb 13 '21 19:02 silviuaavram

The problem is that the typescript interface for React.HTMLProps<HTMLInputElement> that getInputProps returns is imposing an opinion on the shape of the return value that forces the consumer to work around that shape. I assume this is because it's expected that these props will be applied to a plain HTMLInputElement rather than a custom component.

In the example I gave I created a CustomInput component that had an optional custom spellCheck prop which differs from the spellCheck prop on the React.HTMLProps<HTMLInputElement> interface. Because getInputProps returns something that extends React.HTMLProps<HTMLInputElement> typescript complains because the two interfaces don't match.

In the simple example I gave, to work around the issue I'd have to explicitly pass in spellCheck: undefined which feels unnecessary.

If the return type were changed to only contain only those props that Downshift actually cared about the typescript warning would go away.

MarkFalconbridge avatar Feb 15 '21 08:02 MarkFalconbridge

Maybe we should also take into account to fix all return types. Related to this: https://github.com/downshift-js/downshift/pull/1246

I'd rather have a large PR to fix as many types as possible, as these PRs are breaking changes, unfortunately.

Does it make sense @MarkFalconbridge ?

silviuaavram avatar Mar 09 '21 07:03 silviuaavram

Yes, that makes sense to me.

MarkFalconbridge avatar Mar 09 '21 08:03 MarkFalconbridge

I think the type for useCombobox are more accurate. I will not update downshift anymore, so maybe consider using useCombobox.

export interface UseComboboxGetInputPropsOptions
  extends GetInputPropsOptions,
    GetPropsWithRefKey {}
// ...
  getInputProps: (
    options?: UseComboboxGetInputPropsOptions,
    otherOptions?: GetPropsCommonOptions,
  ) => any

silviuaavram avatar Dec 19 '22 16:12 silviuaavram