jaredpalmer / formik

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

Field component with no code completion and no types #2524

Open jazithedev opened 4 years ago

jazithedev commented 4 years ago

📖 Documentation

import { Field } from 'formik';

interface Props {
  name: string;
}

const MyComponent: React.FC<Props> = (props: Props) => {
  return (
    <Field name={props.name}>
      {({ field, form }) => (
        ...
      )}
    </Field>
  );
};

There are two things:

  1. PhpStorm IDE has no code completion on Field. It does not know what props it takes.
  2. Typescript is throwing me an error for field and form variables, that they have any type.

The question is, whether something is wrong in my project, or is this a global issue with Formik.

johnrom commented 4 years ago

Reproduced: https://codesandbox.io/s/formik-typescript-playground-dg32w?file=/pages/index.tsx

m-rutter commented 4 years ago

I think its been like this for a little while. I'm trying to figure out what is wrong with FieldAttributes, but essentially component, render, and children are all failing to provide any kind of type information. They all have the type of any.

m-rutter commented 4 years ago

In fact the entire Field prop type is: any

m-rutter commented 4 years ago

Part of the problem is that Field takes FieldAttributes<any> as its prop type, but FieldAttributes<T> includes the intersection & T, which means that FieldAttributes gets cast to any. However, even if you fix that there are still more problems. My guess is nobody has been looking after Field very well since useField was released.

jaredpalmer commented 4 years ago

Yeah I’ve tried a bunch of times. Forgetting nested dot paths (which as makes it impossible), another problem is also type corrrectness vs. utility. We could restrict field but then you couldn’t use it as easily.

I actually have a solution for Field as= getting proper type inference in addition to forwardRef. Can push up today. GitHub notifications@github.com wrote: “Part of the problem is that Field takes FieldAttributes as its prop type, but FieldAttributes includes the intersection & T, which means that FieldAttributes gets cast to any.”

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.

m-rutter commented 4 years ago

In some cases it can be hard to create an API that is both type safe and easy to use. We probably need some kind of patch pushed because now users of the component are getting no type feedback at all. If you do it fix though you might need to expect to get a lot of confused users complaining that they are getting type errors.

With respect to as you might be able to create a type mapping that defaults the intersection the different input element types if as is undefined, but otherwise maps to the correct type.

m-rutter commented 4 years ago
type As = "input" | "select" | "textarea";

type GenericFieldHTMLAttributes<
  T extends As | undefined = undefined
> = T extends undefined
  ? JSX.IntrinsicElements["input"] &
      JSX.IntrinsicElements["select"] &
      JSX.IntrinsicElements["textarea"]
  : T extends "input"
  ? JSX.IntrinsicElements["input"]
  : T extends "select"
  ? JSX.IntrinsicElements["select"]
  : T extends "textarea"
  ? JSX.IntrinsicElements["textarea"]
  : never;

type InputTypeTest = GenericFieldHTMLAttributes<"input">;
type IntersectionTypeTest = GenericFieldHTMLAttributes;

EDIT: used a union instead of an intersection by mistake

johnrom commented 4 years ago

I was pretty sure I handled a bunch of these cases in #1336 over v1 (besides strongly typing name) by changing the order of the types (T & GenericHTMLAttributes vs GenericHTMLAttributes & T, for example)

It was a long time ago now, but I am pretty sure it fixed a ton of inference problems.

m-rutter commented 4 years ago

The order of the intersections does not matter. All intersections that include any are any:

type Foo = number & any; // any
type Bar = any & number; // any
johnrom commented 4 years ago

Well, I don't think I ended up needing to reorder types (I think that was a bug with a specific typescript version), but I did fully type component and render props in the PR above. Those GenericFieldHTMLAttributes would be a great addition, as long as they allow as={CustomComponent} to use props that differ entirely from IntrinsicElements (it looks like the never achieves that goal but don't have time to test).

johnrom commented 4 years ago

I got close but I hit a wall (and didn't write down where...) here: https://github.com/formium/formik/pull/2655

horne3754sg commented 1 year ago

Hi, I ran into this issue and as a work around just to get types working for my form components, I just set T to unknown FieldAttributes<unknown> and that exposes type hinting.

LazzyLizzard commented 8 months ago

Hi, I ran into this issue and as a work around just to get types working for my form components, I just set T to unknown FieldAttributes<unknown> and that exposes type hinting.

Could you please provide more details or code example please?