jaredpalmer / formik

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

Allow FormikErrors values to be type "any" for, i18n support #1292

Open agwells opened 5 years ago

agwells commented 5 years ago

🐛 Bug report

It looks like at one point, the FormikErrors type allowed errors to be type any, which was added in bug #266, to support i18n frameworks. But over the course of a couple of TypeScript upgrades, this got dropped, and the type was changed to string. I'd like to change it back to any, to once again make it easier to use with i18n frameworks (or just to put other React elements in error messages).

Current Behavior

When I try to return a React element as an error in a Formik validate() method, I receive a TypeScript error, saying that it must be a string:

[ts] Type 'Element' is not assignable to type 'string'. [2322]
error.tsx(6, 3): The expected type comes from property 'name' which is declared here on type 'FormikErrors<Values>'

Expected behavior

The code should compile successfully, with the supplied React element assigned to formik.errors.name.

Reproducible example

import React from 'react';
import {FormikErrors} from 'formik';
import {Trans} from '@lingui/macro';

type Values = {
  name: string
}

function validate(values: Values): FormikErrors<Values> {
  return {
    name: <Trans>error</Trans>;
  }
}

Suggested solution(s)

It looks like it's an easy fix by changing the type in types.tsx from string to any.

Your environment

Software Version(s)
Formik 1.4.2
React 16.7.0
TypeScript 3.2.2
Browser n/a
npm/Yarn 6.7.0
Operating System Ubuntu 16.04
jaredpalmer commented 5 years ago

Yeah this has been suggested before. I wonder if there is a way to maybe uses generic here but default it to string.

agwells commented 5 years ago

Good idea! Since FormikErrors is already a generic, it'd be simple enough to add a second generic parameter for the type of the errors, and give it a default type. I think something like this should work:

export type FormikErrors<Values, ErrorMessage = string> = {
  [K in keyof Values]?: Values[K] extends object
    ? FormikErrors<Values[K]>
    : ErrorMessage
};

I'll update my merge request.

agwells commented 5 years ago

It turns out it's not as simple as adding a second parameter to FormikErrors. In order for the new error message type to be available in places like setFieldError, for example, you also wind up having to parameterize FormikActions, which means you need to parameterize FormikProps, etc, until nearly every type in the library has an extra parameter for the error message type. See: https://github.com/jaredpalmer/formik/pull/1293/commits/30206b0e75d6836f7604506b9b4ee77a280697a9

I'm pretty new to TypeScript, though, so maybe I'm missing a simpler solution?

jaredpalmer commented 5 years ago

This is why it’s been avoided in the past. Types are a balancing act between safety and verbosity.

agwells commented 5 years ago

In that case, I guess I go back to proposing we just loosen the type for error messages, from string to any. :)

ashkan-pm commented 4 years ago

I think this is still unresolved. The only type of error allowed right now is string which is really limiting.

meedodk commented 1 year ago

Has anyone come by a workaround on this issue?

hamoly commented 1 month ago

:D any fixes ?