willowtreeapps / react-formable

React Forms
25 stars 5 forks source link

Typescript interface for forms #88

Closed kaw2k closed 6 years ago

kaw2k commented 7 years ago

I am debating how to structure the interface for a Form value. In the asynchronous validation re-write I am changing from:

interface IForm {
    fieldValues: any;
    fieldErrors: any;
    errors: any[];
    valid: boolean;
}

To...

interface IValidation {
    fieldErrors: any;
    errors: any[];
    valid: boolean;
}

interface IForm {
    fieldValues: any;
    validation: Promise<IValidation>;
}

Will do some A/B testing on this and open it up to a beta version soon. The question is how can we remove the any usage. I am not so sure we can fix fieldErrors or errors but we can use generics to set fieldValues, something like this...

interface IForm<T> {
    fieldValues: T;
    validation: Promise<IValidation>;
}

type MyForm = IForm<{ name: string }>;

I have been bitten multiple times in the past by not typing my form value, this should alleviate those errors. For those who don't want to type it, you can pass in any instead of an object.

Thoughts on this matter?

davesroka commented 7 years ago

@kaw2k I still haven't really dug too much into actually using the form, but I like using generic instead of any for the fieldValues. What's the reasoning being fieldValues being a single object of generic type versus an array of values?

kaw2k commented 7 years ago

Yea, I think we will try generics. Seems like there are simple workarounds for people who don't care for specificity. However chances are if you are using types, you do care about it, so there is that. 😂

I chose to use an object over an array for several reasons:

  1. It modeled the data better. Forms can have lists of data and sets of data. Lists obviously translated to an array, sets easily were modeled as objects.
  2. Most importantly, it is more convenient when accessing the data as an end user. With an object you can just use dot notation to traverse your form's result.
<Form ref="form">
    <Input name="username" />
    <Input name="password" />

    <Fieldset name="meta">
        <Input name="newsletter" />
    </Fieldset>
</Form>

With this form you can access the fields simply:

type MyForm = IForm<{
    username: string;
    password: string;
    meta: {
        newsletter: string;
    };
}>;

const { fieldValues } =  this.refs.form.serialize();
// fieldValues.username
// fieldValues.meta.newsletter

With an array notation it would be quite tedious to access these values without helpers. Maybe I am missing use cases (or misunderstood the question), would love more feedback / other thoughts on the matter 😄