formik icon indicating copy to clipboard operation
formik copied to clipboard

Field component with no code completion and no types

Open jazithedev opened this issue 4 years ago • 13 comments

📖 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.

jazithedev avatar Jun 12 '20 08:06 jazithedev

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

johnrom avatar Jun 12 '20 14:06 johnrom

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 avatar Jul 17 '20 10:07 m-rutter

In fact the entire Field prop type is: any

m-rutter avatar Jul 17 '20 10:07 m-rutter

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.

m-rutter avatar Jul 17 '20 10:07 m-rutter

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 [email protected] wrote: “Part of the problem is that Field takes FieldAttributes as its prop type, but FieldAttributes<T> 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.

jaredpalmer avatar Jul 17 '20 12:07 jaredpalmer

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 avatar Jul 17 '20 13:07 m-rutter

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

m-rutter avatar Jul 17 '20 13:07 m-rutter

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.

johnrom avatar Jul 17 '20 14:07 johnrom

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

m-rutter avatar Jul 17 '20 14:07 m-rutter

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 avatar Jul 17 '20 15:07 johnrom

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

johnrom avatar Jul 30 '20 14:07 johnrom

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.

horne3754sg avatar Aug 04 '23 07:08 horne3754sg

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?

LazzyLizzard avatar Mar 24 '24 14:03 LazzyLizzard