Is there a way to limit `TFieldName` to specific field types when using `react-hook-form`?

I am working with a react-hook-form component:

interface FormFieldInputLabelProps<
  TFieldValues extends FieldValues = FieldValues,
  TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> {
  control: Control<TFieldValues>;
  name: TFieldName;
}

export function FormFieldInputLabel<
  TFieldValues extends FieldValues = FieldValues,
  TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>({ name, control }: FormFieldInputLabelProps<TFieldValues, TFieldName>) {
  const { label } = useFieldContext();
  const { field } = useController({
    control,
    name,
    defaultValue: label
  });

  return <input type="hidden" {...field} />;
};

Although it functions correctly, I encountered an issue when trying to assign the label (a string) as the defaultValue of the field. The error message displayed is:

Type 'string' is not assignable to type 'UnpackNestedValue<PathValue<TFieldValues, TFieldName>>'.ts(2322)

It seems that there may be uncertainty regarding whether

UnpackNestedValue<PathValue<TFieldValues, TFieldName>>
will always be a string... Is there a way to ensure that the provided name indeed corresponds to a value of type string?


Access the codesandbox demonstrating the warning and intended usage here:

https://codesandbox.io/s/condescending-kare-38kdzm?file=/src/App.tsx

Answer №1

Initially, my understanding mirrored yours—field values can be of type any, leading to the possibility of keys having diverse types. This means that a TFieldName should encompass all possible string values for path keys.

While it is theoretically feasible to recursively filter properties of a specific type and paths within that type, I have not been able to accomplish this in your scenario. Thus, I suspect the issue may not lie in coercing any values into strings.

One potential explanation could be that the TFieldName might actually be empty, resulting in a legal union type of never | undefined which are not strings.

export declare type UseControllerProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
    name: TName;
    rules?: Omit<RegisterOptions<TFieldValues, TName>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;
    shouldUnregister?: boolean;
    defaultValue?: FieldPathValue<TFieldValues, TName>;
    control?: Control<TFieldValues>;
};

Hence, unless you provide a minimum, non-empty FieldValues, you may need to adjust the typing as follows:

  const { field } = useController({
    control,
    name,
    defaultValue: label as FieldPathValue<TFieldValues, TFieldName>
  });

[Edit]

When the type is known, TypeScript can infer the resulting type accurately: For example:

const variable = PathValue<FieldValues, FieldPath<FieldValues>>
, where variable is inferred as any due to the known type. But with templates like TFieldValue, TypeScript struggles to predict valid values, resulting in unresolved types within the template.

[Edit 2] Here is a simple example illustrating TS "limitation"

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

Is there a way to modify component data in Angular 5 from another component?

I have a dashboard setup where the main component stays consistent across all pages, while another component, the load component, changes based on the router-outlet. My goal is to hide the "manage load" button in the dashboard component if I delete all loa ...

Best practices for updating the DOM in Angular 7 without needing access to the original source code

I am faced with a situation where I need to manipulate the CSS classes of an element generated by a third-party library for which I do not have access to the source code. While Angular typically recommends a specific method for adding and removing classes ...

Troubleshooting the Hover Effect of Buttons in Next.js when Using Tailwind CSS for Dynamic Color Changes

Encountering a problem with button hover functionality in a Next.js component using Tailwind CSS. The objective is to alter the button's background color dynamically on hover based on a color value stored in the component's state. This code func ...

Changing dates in JavaScript / TypeScript can result in inaccurate dates being displayed after adding days

Recently, I encountered an issue with a simple code snippet that seems to produce inconsistent results. Take a look at the function below: addDays(date: Date, days: number): Date { console.log('adding ' + days + ' days'); con ...

Change the Angular Material 2 theme from light to dark with a simple click

I'm working on an Angular 2 Material project and I want to be able to switch the theme from dark to light with a single click of a button. Can anyone help me figure out how to achieve this? Any tips or advice would be greatly appreciated! ...

It appears that you are currently utilizing legacy implementation in your code. To ensure optimal performance, we recommend updating your code by incorporating createWrapper() and wrapper.useWrappedStore()

I am encountering an issue while using redux toolkit with Next.js. I am receiving the following legacy warning- /!\ You are using a legacy implementation. Please update your code: use createWrapper() and wrapper.useWrappedStore(). I am unsure of whe ...

When attempting to create a fresh NestJS module, a message pops up stating: "An error occurred while

Currently running MacOS Monterey with the M1 chip as my OS. I installed NestJS CLI using the command: sudo npm install -g @nestjs/cli When creating a new Nest project with nest new message, everything goes smoothly. However, when attempting to generate a ...

Learning to implement forwardRef in MenuItem from Material-UI

Encountering an error when pressing Select due to returning MenuItem in Array.map. Code const MenuItems: React.FC<{ items: number[] }> = (props) => { const { items } = props; return ( <> {items.map((i) => { return ( ...

Implementing SSL CA Bundle in NodeJS 14

Currently, I am in the process of integrating a CA Bundle with NodeJS 14.0. I found instructions on Namecheap's website that have been helpful thus far, but I need some further clarification on a couple of points: What file formats are accepted for t ...

Creating a custom class to extend the Express.Session interface in TypeScript

I'm currently tackling a Typescript project that involves using npm packages. I am aiming to enhance the Express.Session interface with a new property. Here is an example Class: class Person { name: string; email: string; password: strin ...

Is time-based revalidation in NextJS factored into Vercel's build execution time?

Currently overseeing the staging environment of a substantial project comprising over 50 dynamic pages. These pages undergo time-based revalidation every 5 minutes on Vercel's complimentary tier. In addition, I am tasked with importing data for numer ...

When incorporating Typescript into HTML, the text does not appear in bold as expected

Issue with bold functionality in Typescript Hey there, I am currently involved in an Angular project and I came across a problem with a function in a Typescript file that is supposed to bold a specific segment of text formatText() { ......... ...

"Although a generic type is compatible with a function argument for mapping, it may not work with

interface DataGeneric { value: number; } function transform<D extends DataGeneric>(data: DataGeneric[], get_value: (record: D) => number) { // No errors, works fine let values = data.map(get_value); // However, this line causes a ...

Creating a typescript object shape without an index signature involves specifying the exact properties

I have a query regarding a potential design gap in TypeScript. Consider a function that accepts objects meeting a specific interface: interface Params { [key: string]: string | number | boolean | undefined | null; } This interface specifies that the k ...

Tips for preserving data upon page refresh in angular 2/4

As a newcomer to Angular2/4, I am facing an issue where the details fetched and saved in my interface are disappearing upon interface refresh. How can this problem be resolved without losing the interface details after a refresh? Here is my Login.componen ...

Storing a variety of values within a formControl in Angular

I'm currently working on a form that involves managing an array of quantity materials in TypeScript. These materials can be added or removed from an inventory and are displayed in the HTML using ngFor. My goal is to allow the FormControl to accommodat ...

Tips for integrating TypeScript files into Next.js HTML files

Encountering an issue while trying to load a typescript file from HTML, resulting in this error Here is the code snippet for the page: export default function Home() { return ( <> <Script src="/static/main.tsx"></Scri ...

Is it possible to access NgbdModalContent properties from a different component?

If I have a component with a template containing an Edit button. When the user clicks on it, I want to load another component as a dynamic modal template. The component is named ProfilePictureModalComponent and it includes the Edit button: (Angular code h ...

Issue with RxDB: Collection not found upon reload

Exploring the integration of RxDB in my Angular project. I wanted to start with a simple example: export const LANG = { version: 0, title: "Language Key", type: "object", properties: { key: { type: "string", primary: true } }, requ ...

Swap the value of a button's text using a dropdown list when clicked in VueJS with TypeScript

I have a button with a click event that opens a dropdown list. I would like for the button text to be updated and for the selected option to be removed from the dropdown list when the user makes a selection. Currently, using {{interestSortingOptions.label} ...