1

I created a reproducible example.
My question is this: how to fix this typescript error with react-final-form?
The error is:

Type '{ name: string; onBlur: (event?: FocusEvent<HTMLElement>) => void; onChange: (event: any) => void; onFocus: (event?: FocusEvent<HTMLElement>) => void; type?: string; value: T; checked?: boolean; multiple?: boolean; }' is not assignable to type 'T'.
  '{ name: string; onBlur: (event?: FocusEvent<HTMLElement>) => void; onChange: (event: any) => void; onFocus: (event?: FocusEvent<HTMLElement>) => void; type?: string; value: T; checked?: boolean; multiple?: boolean; }' is assignable to the constraint of type 'T', 
but 'T' could be instantiated with a different subtype of constraint '{}'.

You can easily see it by clicking the link above.
I saw this great answer, but I don't know how to apply it to this case.

nickbullock
  • 6,424
  • 9
  • 27

1 Answers1

2

It appears to be complaining that ComponentType does not necessarily have the properties from FieldRenderProps that you are attempting to apply to your Component object. You need to write the types so that it understands that your component will always have these properties.

import React, { ComponentType, FC } from 'react';
import { FieldRenderProps, FieldInputProps } from 'react-final-form'

type ComponentBaseProps<T> = FieldInputProps<T> & Record<string, any>

const createAdapter = <T, >(Component: ComponentType<ComponentBaseProps<T>>) => {
  return ({ input, meta, ...rest }: FieldRenderProps<T>): JSX.Element => {
    return <Component {...input} {...rest} />
  }
}

The above types will inform typescript that the Component you are providing has all the properties you are attempting to assign, all the properties that make up your:

  • input variable (of type FieldInputProps)
  • rest variable (of type Record<string, any>)

The other thing to note is that the generic argument for ComponentType is the complete set of properties that apply to the component, while the generic argument for FieldRenderProps is the type of your form data. Using T directly for both is what was giving you your mismatch.

Jacob Smit
  • 2,206
  • 1
  • 9
  • 19
  • Thanks for your answer! But it seems that the type generated by typescript with this code is incorrect. I updated stackblitz, please take a look on it one more time. The type is `React.FunctionComponent>`, but it should be `React.FunctionComponent>`, in my example `React.FunctionComponent>` – nickbullock Jul 24 '20 at 11:44
  • Sorry, had a busy weekend. I think this has to do with how the Material UI inputs are typed for their value property. If you create a constant of type TextFieldProps or InputProps and then attempt to access its value property you will notice that the value is unknown (`const test: TextFieldProps = { value: 'string' };` and then `test.value` is unknown). – Jacob Smit Jul 26 '20 at 21:28
  • The only thing I can suggest, which I think in the long run you will have to do anyway if you start using slightly more complex inputs, is to create more specific input adaptors and type them appropriately. I will make an example, but I understand this doesn't exactly solve your problem and is more of an alternative. – Jacob Smit Jul 26 '20 at 21:31
  • Something more like this: [https://stackblitz.com/edit/create-adapter-1svdsm?file=index.tsx](https://stackblitz.com/edit/create-adapter-1svdsm?file=index.tsx) – Jacob Smit Jul 26 '20 at 21:52
  • Yeah, you're right about complex adapters. For complex components we need complex adapters. But I believe for simple adapters we can create one function and it will generate the correct type. I updated stackblitz one more time - take a look, it doesn't matter what components are used, mui or antd - type is correct. But I still don't know how to handle this error and get the correct type. Anyway, thanks for your help. https://stackblitz.com/edit/create-adapter?file=index.tsx – nickbullock Jul 27 '20 at 07:21
  • The type isnt 100% correct, as the FieldValue generic should be the type of the field, not the type of the input's properties, e.g. string not InputProps. – Jacob Smit Jul 27 '20 at 08:25