Incorrect TypeScript typings for render function of FieldArray, et al
Opened this issue · 0 comments
Describe the bug
The FieldArray
; FieldControl
and FieldGroup
components all share the same render function type definition via the GroupProps
interface:
render?: (
control: FormArray | FormControl | FormGroup
) => React.ReactElement<any> | React.ReactElement<any>[]
However, FieldArray
will actually always use a FormArray
; FieldControl
will always use a FormControl
; and FieldGroup
will always use a FormGroup
.
The use of a union type on the render function and forcing these three distinct signatures to be squished together means that when accessing any implementation-specific members such as the controls
array on a FormArray
, explicit type narrowing has to be added.
It's not possible to simply define the control
prop in the callback to narrow the type, e..g
<FieldArray render="{( control: FormArray ) => {
// ...
})}"/>
as this is a TS compiler error due to an incompatible type signature between the provided render function and its declared type on GroupProps
. The callback needs to be able to accept anything matching the union type.
So what's left is two options:
Either add actual logic in the render function in the vein of if (control instanceof FormArray) {
or hard casts in the render function body, which is purely ceremonious overhead and is, basically, noise. Because the underlying type will de facto always be the narrowed one we expect.
Or we apply type erasure with any
, e.g.
<FieldArray render="{( control: any ) => {
// ...
})}"/>
which is pretty damn bad. Because, well: it's type erasure. There goes type safety...
Expected behavior
The render function is appropriately typed with the right type of control
for each of the three component types.
This could for instance be achieved by turning GroupProps
into a generic interface that allows passing the expected control type, so that we get e.g.
export class FieldGroup extends React.Component<GroupProps<FormGroup>, any> {}
export class FieldArray extends React.Component<GroupProps<FormArray>, any> {}
export class FieldControl extends React.Component<GroupProps<FormControl>, any> {}