remix-validated-form icon indicating copy to clipboard operation
remix-validated-form copied to clipboard

[Bug]: Typescript error when using getInputProps with react-select

Open zayenz opened this issue 2 years ago • 6 comments

Which packages are impacted?

  • [X] remix-validated-form
  • [X] @remix-validated-form/with-zod
  • [ ] @remix-validated-form/with-yup
  • [X] zod-form-data

What version of these packages are you using?

"dependencies": {
    "@remix-run/react": "^1.2.3",
    "@remix-run/serve": "^1.2.3",
    "remix-validated-form": "^4.1.8",
    "@remix-validated-form/with-zod": "^2.0.1",
    "zod": "^3.13.4",
    "zod-form-data": "^1.2.0"
    "zod-form-data": "^1.2.0"
    "react-select": "^5.2.2",
},
"devDependencies": {
    "@remix-run/dev": "^1.2.3",
    "@types/react": "^17.0.40",
    "@types/react-dom": "^17.0.13",
    "typescript": "^4.6.2"
}

Please provide a link to a minimal reproduction of the issue.

https://gist.github.com/zayenz/b9e6ca74773481f8eeb827543850d27a

Steps to Reproduce the Bug or Issue

With the file in the gist as a route in a remix app, typechecking gives an error for the use of getInputProps for ReactSelect.

app/routes/test.tsx:34:21 - error TS2345: Argument of type '{ id: string; options: { value: string; label: string; }[]; isMulti: boolean; }' is not assignable to parameter of type 'Omit<MinimalInputProps, HandledProps | Callbacks> & Partial<Pick<MinimalInputProps, Callbacks>>'.
  Object literal may only specify known properties, and 'id' does not exist in type 'Omit<MinimalInputProps, HandledProps | Callbacks> & Partial<Pick<MinimalInputProps, Callbacks>>'.

34                     id: "fruits",
                       ~~~~~~~~~~~~

Expected behavior

I would have expected to be able to use getInputProps with react-select input element, as is done without problem for the standard input element.

Note that running the code works fine, so it seems to be a typing problem and not an issue with the behaviour.

Screenshots or Videos

No response

Platform

  • OS: macOS
  • Browser: typescript
  • Version: [e.g. 91.1]

Additional context

See discussion in https://github.com/airjp73/remix-validated-form/discussions/80 for more context.

zayenz avatar Mar 11 '22 14:03 zayenz

It seems that TS has trouble inferring the generic for getInputProps in cases where the props of the component are a fairly complex type. It looks like this is definitely the case for react-select

type Test = ComponentProps<typeof ReactSelect>;
// Omit<Pick<Props<unknown, boolean, GroupBase<any>>, "aria-errormessage" | "aria-invalid" | "aria-label" | "aria-labelledby" | "ariaLiveMessages" | "autoFocus" | ... 24 more ... | "form"> & Partial<...> & Partial<...>, StateManagedPropKeys> & Partial<...> & StateManagerAdditionalProps<...> & React.RefAttributes<...>

I'm not sure if there's a way to improve TS's ability to do this, so the fix is to provide the generic directly.

import ReactSelect, { Props } from 'react-select';

<ReactSelect {...getInputProps<Props>({ id: 'my-select' })} />

Sandbox.

It's probably worth documenting this limitation in the docs somewhere, so I'll leave this issue open until that gets added.


Related to #59 and #31.

airjp73 avatar Mar 12 '22 15:03 airjp73

Thanks for the detailed answer, this clarified a lot for me. I agree that some additional documentation would help.

zayenz avatar Mar 14 '22 13:03 zayenz

Hey, I have also encountered typing errors using getInputProps with Ariakit and it seems that the function can’t handle generic types, so that it’s worth mentioning in docs that one can explicit pass a generic type to getInputProps.

For a reference here is the link to discussion on Ariakit https://github.com/ariakit/ariakit/discussions/1614 with following example:

WithoutGenerics(props: InputHTMLAttributes<HTMLInputElement>) {
  return null;
}

function WithGenerics<T extends InputHTMLAttributes<HTMLInputElement>>(props: T) {
  return null;
}

// works
<WithoutGenerics {...getInputProps({ type: "checkbox", checked: false })} />

// error
<WithGenerics {...getInputProps({ type: "checkbox", checked: false })} />

kwiat1990 avatar Jul 12 '22 05:07 kwiat1990

The type definitions for getInputProps should be less restrictive and accept any prop in addition to its own props. Then, return the combined object shape and let the component handle the prop type validation.

TS Playground

Screenshot of the TypeScript code in the link above

diegohaz avatar Jul 12 '22 05:07 diegohaz

That would guarantee a more correct typing, but we would lose the autocomplete when typing inside getInputProps. I wonder if there's a way to get the best of both worlds?

airjp73 avatar Jul 12 '22 12:07 airjp73

as of now I see no way to use anything from headlessui (i.e. https://headlessui.com/react/combobox) as the prop types just don't mesh with getInputProps..

alexbu92 avatar Oct 05 '22 17:10 alexbu92