Ways to dynamically access input errors

Exploring My Implementation

I have devised a function that takes an argument to access specific formik errors dynamically. This requires using bracket notation instead of dot notation as shown below:

import {useFormikContext} from 'formik';

function TextField(name: string): JSX.Element {
  const {errors} = useFormikContext();
  console.log(errors[name]); // TypeScript error occurs here
  
  // other function/component code
}

The Challenge at Hand

Although the code functions properly and retrieves errors based on the passed name as a string, I am encountering TypeScript errors:

errors[name]: TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'FormikErrors<unknown>'. No index signature with a parameter of type 'string' was found on type 'FormikErrors<unknown>'.

My Desired Outcome

While I have reviewed the types provided by formik, I am struggling to create a function that accepts the error name as an argument without raising TypeScript complaints.

Revised Approach

Our current issue: attempting to retrieve errors dynamically using bracket notation. How can we incorporate FormData in this scenario?

import {getIn, useFormikContext} from 'formik';
import React from 'react';
import {Input as UIKInput} from '@ui-kitten/components';

import {InputProps as UIKInputProps} from '@ui-kitten/components/ui/input/input.component';

export type TextFieldProps = UIKInputProps & {
  name: string;
};

export default function TextField(props: TextFieldProps): JSX.Element {
  const {name, ...inputProps} = props;
  const {setFieldTouched, handleChange, errors, touched} = useFormikContext();

  return (
    <UIKInput
      status={errors[name] && touched[name] ? 'danger' : 'basic'}
      caption={
        errors[name] && touched[name] ? errors[name] : ''
      }
      onBlur={() => setFieldTouched(name)}
      onChangeText={handleChange(name)}
      {...inputProps}
    />
  );
}

Further Refinement

Utilizing getIn to access specific errors or touched states while avoiding type errors.

import {getIn, useFormikContext} from 'formik';
import React from 'react';
import {Input as UIKInput} from '@ui-kitten/components';

import {InputProps as UIKInputProps} from '@ui-kitten/components/ui/input/input.component';

export type TextFieldProps = UIKInputProps & {
  name: string;
};

export default function TextField(props: TextFieldProps): JSX.Element {
  const {name, ...inputProps} = props;
  const {setFieldTouched, handleChange, errors, touched} = useFormikContext();

  return (
    <UIKInput
      status={getIn(errors, name) && getIn(touched, name) ? 'danger' : 'basic'}
      caption={
        getIn(errors, name) && getIn(touched, name) ? getIn(errors, name) : ''
      }
      onBlur={() => setFieldTouched(name)}
      onChangeText={handleChange(name)}
      {...inputProps}
    />
  );
}

Answer №1

The issue arises because the variable name is a string, and the errors object only accepts specific strings as keys, not all strings. To resolve this, you need to ensure the type system recognizes the existing keys and restrict the usage to those specific keys.

If you hover over useFormikContext(), a type popup should appear as follows:

useFormikContext<unknown>(): FormikContextType<unknown>

The <unknown> indicates that it expects a type that matches the shape of the form data. By providing this type, everything should function as intended.

For example, if your form data is structured like this:

interface FormData {
  firstName: string
  lastName: string
}

You can define your component props to only accept values that are keys of the form data:

interface Props {
  formKey: keyof FormData
}

Lastly, you should pass FormData as the type argument to useFormikContext():

const { errors } = useFormikContext<FormData>();
console.log(errors[formKey]); // no issues here

This method ensures type safety and will raise a type error if an incorrect key is provided:

// Valid
const testUsage = <TextField formKey='firstName' />

// Error: Type '"keyDoesNotExist"' is not assignable to type 'keyof FormData'.
const badUsage = <TextField formKey='keyDoesNotExist' />

View the example on Typescript Playground

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The function cannot be accessed during the unit test

I have just created a new project in VueJS and incorporated TypeScript into it. Below is my component along with some testing methods: <template> <div></div> </template> <script lang="ts"> import { Component, Vue } from ...

In Typescript, develop a tuple type that repeats itself

My API, specifically the Elasticsearch bulk API, requires an array of operations where each operation is a pair. The first element in the pair specifies the operation (index, update, create, delete) and the second element contains the data (excluding delet ...

The utilization of functions from a implemented interface results in the generation of a 'non-function' error

I recently created an interface that includes variables and a function. However, I encountered an issue when trying to utilize the implemented function for a specific class as it resulted in an 'ERROR TypeError: ...getPrice is not a function" Below ...

Is it possible for an app's feature module to access routing configurations from another lazily loaded module in Angular routing?

The functionality of our App is divided into multiple feature modules that are lazily loaded. Each module is loaded under different path matches, and some modules import a shared module containing reusable components. Everything seems to be working well so ...

Tips for streamlining interface initialization and adding items to it

I have designed an interface that includes another interface: export interface Parent { children: Child[]; } export interface Child { identifier: string; data: string; } Is there a more efficient way to initialize and add items to the array? Curren ...

Using TypeScript to specify a limited set of required fields

Can a custom type constraint be created to ensure that a type includes certain non-optional keys from an object, but not all keys? For instance: class Bar { key1: number key2: Object key3: <another type> } const Y = { key1: 'foo' ...

What are the appropriate Typescript typings for React Components that have the ability to return a string or their child components directly?

What are the suitable types for a React Component that can also output a string or directly its children, in addition to a JSX.Element? For example: type PropsStringExample = Readonly<{ returnString: boolean; }>; type PropsChildrenExample = Readon ...

ESLint version 8.0.0 encountered an error while attempting to fetch the '@typescript-eslint' plugin

Hey there, I'm in need of some assistance. I encountered an error while trying to build a project. Uh-oh! Something didn't go as planned! :( ESLint: 8.0.0 TypeError: Failed to load plugin '@typescript-eslint' specified in ' ...

Retrieve a prepared response from a TypeORM query

I need to retrieve all the courses assigned to a user with a simple query: There are 2 Tables: students & courses return await this.studentsRepository .createQueryBuilder('s') .leftJoinAndSelect('courses', 'c' ...

When conditional types are used to pass unions through generics, the assigned value defaults to 'any' instead of

In search of a universal type to implement in my actions. Actions can vary from simple functions to functions that return another function, demonstrated below: () => void () => (input: I) => void An Action type with a conditional generic Input h ...

I'm stuck trying to figure out all the parameters for the MapsPage component in Angular 2

Currently, I am utilizing Angular2 with Ionic2 for my mobile app development. Everything was working flawlessly until I decided to incorporate a new module for Google Maps navigation. Specifically, I am using phonegap-launch-navigator for this purpose. The ...

Which rxjs operator should be used when dealing with nested subscriptions in the presence of an if statement?

In my Angular/Typescript project, I am dealing with 2 subscriptions. Each subscription is subscribing to its own observable A and B, which are located outside the component in the service file. Sometimes, when A changes, B may or may not change based on c ...

Could the repeated utilization of BehaviorSubject within Angular services indicate a cause for concern?

While developing an Angular application, I've noticed a recurring pattern in my code structure: @Injectable(...) export class WidgetRegsitryService { private readonly _widgets: BehaviorSubject<Widget[]> = new BehaviorSubject([]); public get ...

What is the best way to define a global variable in TypeScript and access it throughout a Vue application?

In my main.ts file, I am looking to define a variable that can be accessed in all Vue files. Within my sfc.d.ts file, the following content is included: declare module '*.vue' { import Vue from 'vue' export default Vue } declar ...

Matching TypeScript against the resulting type of a string literal template

My type declaration looks like this: type To_String<N extends number> = `${N}` I have created a Type that maps the resulting string number as follows: type Remap<Number> = Number extends '0' ? 'is zero' : Number ...

Tips for accessing a RouterState from the @ngxs/router-plugin before and during the initialization of other states

Previously, in an Angular 8.0.0 and 3.5.0 NGXS application, I successfully retrieved the RouterState using SelectSnapshot from the @ngxs/router-plugin within other states before component rendering. However, in my latest application, the RouterState now re ...

The quantity of elements remains constant in the EventEmitter

The Grid component is structured as follows: export class GridComponent { @Output('modelChanged') modelChangedEmitter = new EventEmitter(); private valueChanged(newValue: any, item: Object, prop: string) { item[prop] = newValue; ...

Is it feasible to return data when utilizing the ModalController in Ionic 5, specifically when executing a swipeToClose or backdropDismiss action?

With the latest update to Ionic 5's ModalController, a new feature allows users to swipe down on a modal to close it in addition to using the backdropDismiss parameter. Here is an example of how to enable this functionality: const modal = await this. ...

Resolving the error message "Default props must have construct or call signatures for 'Component' in Typescript"

I'm currently working on a function component called MyComponent and I'm facing an issue with setting a default prop for component. The goal is to have the root node render as a "span" if no value is provided. However, I am encountering the follo ...

What is the syntax for creating ES6 arrow functions in TypeScript?

Without a doubt, TypeScript is the way to go for JavaScript projects. Its advantages are numerous, but one of the standout features is typed variables. Arrow functions, like the one below, are also fantastic: const arFunc = ({ n, m }) => console.log(`$ ...