Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/formHelpers/form-fields.tsx (TypeScript)

Code before:
  return (
    <>
      {formFields
        .filter(formField => !ignored.includes(formField.name))
        .map(({ name, label }) => (
          <Field key={`${name}-field`} name={name}>
            {({ input: { value, onChange }, meta: { pristine, error } }) => {
              const placeholder =
                name in placeholders ? placeholders[name] : '';
              const isURL = types[name] === 'url';
              return (
                <FormGroup key={name}>
                  <ControlLabel
                    htmlFor={name}
                    data-playwright-test-label={`${name}-control-label`}
                  >
                    {label}
                  </ControlLabel>
                  <FormControl
                    id={name}
                    name={name}
                    onChange={onChange}
                    placeholder={placeholder}
                    required={required.includes(name)}
                    rows={4}
                    type={types[name] || 'text'}
                    value={value as string}
                    aria-describedby={`${name}-message`}
                    data-playwright-test-label={`${name}-form-control`}
                  />
                  {nullOrWarning(
                    value as string,
                    !pristine && error,
                    isURL,
                    name
                  )}
                </FormGroup>
              );
            }}
          </Field>
        ))}
    </>
  );
}

FormFields.displayName = 'FormFields';

export default FormFields;


Review comment (suggestion):
If we start allowing dynamic type, the `types` definition should be made stricter.

From:

```ts
types?: { [key: string]: string };
```

To:

```ts
types?: { [key: string]: React.HTMLInputTypeAttribute };
```

Code after:
  return (
    <>
      {formFields
        .filter(formField => !ignored.includes(formField.name))
        .map(({ name, label }) => (
          <Field<string | undefined> key={`${name}-field`} name={name}>
            {({ input: { value, onChange }, meta: { pristine, error } }) => {
              const placeholder =
                name in placeholders ? placeholders[name] : '';
              const isURL = types[name] === 'url';
              return (
                <FormGroup key={name}>
                  <ControlLabel
                    htmlFor={name}
                    data-playwright-test-label={`${name}-control-label`}
                  >
                    {label}
                  </ControlLabel>
                  <FormControl
                    id={name}
                    name={name}
                    onChange={onChange}
                    placeholder={placeholder}
                    required={required.includes(name)}
                    rows={4}
                    type={types[name] || 'text'}
                    value={value as string}
                    aria-describedby={`${name}-message`}
                    data-playwright-test-label={`${name}-form-control`}
                  />
                  {nullOrWarning(
                    value as string,
                    !pristine && error,
                    isURL,
                    name
                  )}
                </FormGroup>
              );
            }}
          </Field>
        ))}
    </>
  );
}

FormFields.displayName = 'FormFields';

export default FormFields;