I have a minimal reproducible example of the problem at the following link:
import React, { useState } from 'react';
type InputValue = string[] | string;
interface InputProps<T extends InputValue> {
value: T;
}
// -------------------------------------------------------------------------------------------------
// TEXT INPUT
// -------------------------------------------------------------------------------------------------
const TextInput = ({ value = '' }: InputProps<string>): React.ReactElement => {
return <input value={value} />;
};
// -------------------------------------------------------------------------------------------------
// FORM FIELD
// -------------------------------------------------------------------------------------------------
interface FormFieldProps<T extends InputValue> {
render: (props: InputProps<T>) => React.ReactElement;
value: T;
}
const FormField = <T extends InputValue>({
render,
value,
}: FormFieldProps<T>): React.ReactElement => (
<div>
{render({ value })}
</div>
);
// -------------------------------------------------------------------------------------------------
// FORM
// -------------------------------------------------------------------------------------------------
interface FieldPropsReturn<T> {
value: T[keyof T];
}
interface UseFormReturn<T> {
fieldProps: (name: keyof T) => FieldPropsReturn<T>;
}
const useForm = <T extends object>(): UseFormReturn<T> => {
const [formData] = useState<T>({} as T);
const fieldProps = (name: keyof T): FieldPropsReturn<T> => ({
value: formData[name],
});
return {
fieldProps
};
};
// -------------------------------------------------------------------------------------------------
// INDEX
// -------------------------------------------------------------------------------------------------
interface IndexFormFields {
fruits: string[];
name: string;
}
const Index = (): React.ReactElement => {
const { fieldProps } = useForm<IndexFormFields>();
return (
<FormField
{...fieldProps('name')}
render={(props): React.ReactElement => <TextInput {...props} />}
/>
);
};
export default Index;
Essentially, I am building some form helpers, including a FormField that renders a form component. I would like these FormField render functions to infer the value type from the key passed to fieldProps, but at the moment it is returning the following error on the TextInput component:
Type '{ value: string | string[]; }' is not assignable to type 'InputProps<string>'.
Types of property 'value' are incompatible.
Type 'string | string[]' is not assignable to type 'string'.
Type 'string[]' is not assignable to type 'string'.
Is there any way that a render function for a FormField with a fieldProps of 'name' will pass a value type of string, and one with a fieldProps of 'fruits' will pass a value type of string[], as per the IndexFormFields interface?