Trouble securing an undefined value in a union type

Encountering an error with the code below that seems unexpected. TypeScript is flagging rules[name] as not being callable, which is true since it can be undefined. Even after guarding against this case, the same error persists. The issue is elaborated in the code comments.

This expression is not callable.
  Not all constituents of type '((value: string | number) => boolean) | undefined' are callable.
    Type 'undefined' has no call signatures.ts(2349)
type FieldValues = Record<string, string | number>;
type FieldName<FormValues> = keyof FormValues;
type FormState<FormValues> = {
  values: FormValues,
  errors: Record<FieldName<FormValues>, boolean>,
  focused: Record<FieldName<FormValues>, boolean>,
  touched: Record<FieldName<FormValues>, boolean>,
  dirty: Record<FieldName<FormValues>, boolean>,
  isValid: boolean,
  isDirty: boolean,
};

export function useForm<FormValues extends FieldValues> (
  defaultValues: FormValues,
  rules?: Partial<Record<FieldName<FormValues>, (value: string | number) => boolean>>,
) {
...

  const validate = (name: FieldName<FormValues>, value: string | number) => {

    // either if (rules && rules[names]) or if (rules && rules[name] instanceof Function) 
    // should narrow out undefined thus guaranteeing the correct call signature
    if (rules && rules[name] instanceof Function) {
      setFormState((prevFormState: FormState<FormValues>) => ({
        ...prevFormState,
        errors: {
          ...prevFormState.errors,
          [name]: rules[name](value),
        },
        isValid: isFormValid({
          ...prevFormState.errors,
          [name]: rules[name](value),
        }),
      }))
    }
  }

...
}

A similar issue has been reported as a bug:

stackoverflow issue

issue on the Typescript repo

Having trouble understanding the reported bug: i) does this fall under the same type of issue and ii) what is the workaround for this?

Edit: changed the title from 'Guarding for function in union type not working' to 'Guarding for undefined in union type not working' as it describes the problem more accurately.

Answer №1

It seems like a straightforward solution is checking the condition like rules && rules[name]. The Typescript compiler recognizes it as either a function or undefined, so verifying that it's truthy should suffice.

Answer №2

If you find yourself encountering a similar issue, a detailed explanation of why TypeScript struggles with these scenarios and a workaround are available here.

Here is the approach I took to address the issue:

   if (rules) {
      const fieldRule = rules[name]

      if (fieldRule) {
        setFormState((prevFormState: FormState<FormValues>) => ({
          ...prevFormState,
          errors: {
            ...prevFormState.errors,
            [name]: fieldRule(value),
          },
          isValid: isFormValid({
            ...prevFormState.errors,
            [name]: fieldRule(value),
          }),
        }))
      }
    }

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

Working with Angular: Managing an Array of Objects

After retrieving an array of objects using the code snippet below: this.serviceOne.getRemoteData().subscribe( data => this.MyArray.push(data) ); I encounter issues when trying to iterate through the array using the code snippet bel ...

Tips on how to retrieve a stubbed Observable<void> in RxJS

Currently, I am attempting to stub an API and would like to retrieve a stubbed response from my Service. The method in my service appears as follows: public addItem(item): Observable<void> { this.listOfItems.push(item); return of(); } As f ...

What could be causing the elements in my array to appear as undefined?

https://i.stack.imgur.com/ze1tx.png I'm stuck trying to understand why I can't extract data from the array. const usedPlatformLog: Date[] = [] users.forEach(el => { usedPlatformLog.push(el.lastUsed) }) console.log(usedPlatformLog) // disp ...

Tips on using the map and filter methods to narrow down a nested array based on specific object

I am struggling to filter JSON data based on a specific date using Array.Filter and Map. The code I have tried below is not yielding the desired results. Can someone please provide guidance on how to effectively filter JSON data based on a particular date ...

Error: The Turborepo package restricts the use of import statements outside of modules

I created a typescript "test" package in turborepo, which imports and exports typescript functions. Due to being in turborepo, it gets copied to node_modules/test. When attempting to run import {func} from "test", an error is thrown: SyntaxError: Cannot ...

I've tried using a ControlValueAccessor, but for some reason the value isn't getting passed to the form

Currently, I am experimenting with reactive forms in Angular, and I'm encountering difficulties with updating the form from custom components. As an example, take a look at the date-input component created using flatpickr in the linked Plunker demo. ...

I am having trouble locating my TypeScript package that was downloaded from the NPM registry. It seems to be showing as "module not found"

Having some challenges with packaging my TypeScript project that is available on the npm registry. As a newcomer to module packaging for others, it's possible I've made an error somewhere. The following sections in the package.json appear to be ...

Adding files to an Angular ViewModel using DropzoneJS

I am facing a challenge in extracting file content and inserting it into a specific FileViewModel. This is necessary because I need to bundle all files with MainViewModel which contains a list of FileViewModel before sending it from the client (angular) to ...

Is there a way to implement jquery (or other external libraries) within Typescript?

Currently, I am diving into Typescript to enhance my skills and knowledge. For a project that is being served with Flask and edited in VSCode, I am looking to convert the existing JavaScript code to Typescript. The main reason for this switch is to leverag ...

Working with JSON data in AngularJS2's templates

Is there a way for me to process JSON from the template in a manner similar to the second code I provided? First code. This method works well when using .json and .map () @Component({ ..// template: `..// <li *ngFor="#user of users"> ...

No issues raised by Typescript/tslint regarding this in arrow function

After making some creative adjustments, this is what I came up with: const TopBar = () => ( <Button onPress={this.onPress} // No errors shown /> ) Although all my other rules in tslint.json are functioning properly. Is there a way to ma ...

Endure the class attribute in Angular 5

My SearchComponent has a route (/search) and SearchDetailComponent has a route (/search-detail:id). In the SearchComponent, there is a searchbox (input field) where I can type any text to start a search. After loading the search results and navigating to ...

Insert an HTML element or Angular component dynamically when a specific function is called in an Angular application

Currently, I am working on a component that contains a button connected to a function in the .ts file. My goal is to have this function add an HTML element or make it visible when the button is clicked. Specifically, I would like a dynamic <div> elem ...

Travis CI's TypeScript build process detects errors before Mocha has a chance to catch them

Instead of a bug, the TypeScript compiler is doing its job but causing my Travis builds to fail. In my package, I have a function named completeRound which accepts a number as its first argument and 3 optional arguments. Since it's in TypeScript, I s ...

The parameter type x cannot be assigned to the argument type '(x) => ObservableInput<{}>'

Looking for some insights on this issue Currently working with ngrx and attempting to utilize multiple switchMaps to call various action classes. Defined Actions: export class BlogAddedAction implements Action { readonly type = BLOG_ADDED_ACTION; ...

Trouble with Nextjs link not functioning properly with a URL object when incorporating element id into the pathname

Recently I added translations to my website, which means I now need to use a URL object when creating links. Everything has been going smoothly with this change except for one issue: when I try to click a link that points to /#contact. When simply using h ...

Having trouble getting a local npm installation to work from a specific file path?

After following the instructions from this helpful link to install an npm package through a file path, I encountered an error when attempting to use it: Cannot find module '<module_name>' or its corresponding type declaration Are there an ...

Simulating service calls in Jest Tests for StencilJs

When testing my StencilJs application with Jest, I encountered an issue with mocking a service class method used in a component. The service class has only one function that prints text: The Component class: import {sayHello} from './helloworld-servi ...

Gulp is failing to create a JavaScript file from TypeScript

Below is the Gulp task I am using: var gulp = require('gulp'); var typescript = require('gulp-typescript'); var sourcemaps = require('gulp-sourcemaps'); var tsProject = typescript.createProject('tsconfig.json'); var ...

What is the most effective way to compare two arrays of objects in JavaScript?

I'm working on a function that needs to return an array of elements based on certain filters. Here is the code for the function: filter_getCustomFilterItems(filterNameToSearch: string, appliedFilters: Array<any>) { let tempFilterArray = []; ...