jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.98k stars 2.79k forks source link

How to add strongly typed field in Formik by typescript? #2068

Open pnrBehnamm opened 4 years ago

pnrBehnamm commented 4 years ago

I tried to add strongly typed in Formik react library by typescript, but I didn't do that. Of course, I have used this link, but I couldn't solve my issue. https://jaredpalmer.com/formik/docs/guides/typescript

I have got this error from this part of code(})(ActivityForm);):

Argument of type '(props: IProps) => Element' is not assignable to parameter of type 'CompositeComponent<object & FormikSharedConfig<{}> & FormikState & FormikHelpers & FormikHandlers & FormikComputedProps & FormikRegistration & { ...; }>'. Type '(props: IProps) => Element' is not assignable to type 'FunctionComponent<object & FormikSharedConfig<{}> & FormikState & FormikHelpers & FormikHandlers & FormikComputedProps & FormikRegistration & { ...; }>'. Types of parameters 'props' and 'props' are incompatible. Property 'setEditMode' is missing in type 'FormikSharedConfig<{}> & FormikState & FormikHelpers & FormikHandlers & FormikComputedProps & FormikRegistration & { ...; } & { ...; }' but required in type 'IProps'.ts(2345) ActivityForm.tsx(7, 3): 'setEditMode' is declared here.

import React from "react";
import * as yup from "yup";
import { withFormik, Form, Field, FormikProps } from "formik";

interface IProps {
  setEditMode: (editMode: boolean) => void;
}

export const ActivityForm = (props: IProps) => {
  const { setEditMode } = props;
  return (
    <Form>
      <Field type="text" name="title" placeholder="Title" />
      <Field
        type="text"
        rows={2}
        name="description"
        placeholder="Description"
      />
      <Field type="text" name="category" placeholder="Category" />
      <Field type="date" name="date" placeholder="Date" />
      <Field type="text" name="city" placeholder="City" />
      <Field type="text" name="venue" placeholder="Venue" />
      <button type="submit">Edit</button>
      <button type="button" onClick={() => setEditMode(false)}>
        Cancel
      </button>
    </Form>
  );
};

const myForm = withFormik({
  mapPropsToValues: props => {
    return {};
  },
  validationSchema: yup.object().shape({
    title: yup.string().required()
  }),
  handleSubmit(values) {
    console.log(values);
  }
})(ActivityForm);

export default myForm;
spawluk commented 4 years ago

Did you tried <Formik<Type> {...}>?

withFormik<
  OuterProps extends object,
  Values extends FormikValues,
  Payload = Values
>

signature suggests it can be done. Second argument is for type of your object you want.

pnrBehnamm commented 4 years ago

I have used Render props (<Formik /> and <Field />) and I fixed my issue.

import * as React from 'react';
import {
  Formik,
  FormikHelpers,
  FormikProps,
  Form,
  Field,
  FieldProps,
} from 'formik';

interface MyFormValues {
  firstName: string;
}

export const MyApp: React.FC<{}> = () => {
  const initialValues: MyFormValues = { firstName: '' };
  return (
    <div>
      <h1>My Example</h1>
      <Formik
        initialValues={initialValues}
        onSubmit={(values, actions) => {
          console.log({ values, actions });
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }}
        render={formikBag => (
          <Form>
            <Field
              name="firstName"
              render={({ field, form, meta }) => (
                <div>
                  <input type="text" {...field} placeholder="First Name" />
                  {meta.touched && meta.error && meta.error}
                </div>
              )}
            />
          </Form>
        )}
      />
    </div>
  );
};
kishaningithub commented 3 years ago

Linking this nice blog post to this thread https://spin.atomicobject.com/2020/10/25/formik-type-safe-paths/