In Typescript, the type of a value within an if statement cannot be predetermined

How can I adjust the onValueChange function in a way that TypeScript recognizes that when field === 'age', val will be of type number? Is there a method to do this without resorting to using 'as number'?

interface IRow {
  age: number;
  name: string;
  born: Date;
  isGood: boolean;
}

const state: IRow = {
  age: 5,
  name: 'bob',
  born: new Date(),
  isGood: true
}

const onValueChange = (field: keyof IRow) => (val: IRow[keyof IRow]) => {
  if (field === 'age') {
    const someNumber = 2 * val; // The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
    state[field] = val; // Type 'string | number | boolean | Date' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'
  }
}

onValueChange('age')(5);

https://codesandbox.io/s/typescript-playground-export-forked-j4cykf?fontsize=14&hidenavigation=1&theme=dark

Answer №1

To define the type of val based on the specific field, you can use a generic parameter to capture it. Currently, your code allows for any combination of field and val, which ensures the function is called correctly.

However, Typescript may have trouble determining the actual type within the generic code, but you can safely cast it to the appropriate type. For example:

const onValueChange = <T extends keyof IRow>(field: T) => (val: IRow[T]) => {
  if (field === 'age') {
    const ageIsNumber = state['age']
    const ageIsAnything = state[field]

    // in this case, val is still restricted to string, number, boolean, or Date
    // but you can safely cast it since calling onValueChange with anything other than a `number` is not allowed
    // e.g. onValueChange('age')('4')
    const someNumber = 2 * (val as number);

    // both are valid IRow[T]
    state[field] = val;
  }
}

It's possible that Typecript 4.9 will bring improvements to type narrowing, but upon testing, there seems to be no change. Edit: just tried it.

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

Overriding a shared module service in Angular from a separate module: A step-by-step guide

I am working with various modules such as SchoolModule, UniversityModule, and SharedModule The SharedModule includes a BaseService that both the SchoolModule and UniversityModule providers are utilizing as an extension When loading the SchoolModule, I ne ...

Encountering an error when attempting to store a value in an array of custom types: "Unable to assign properties to undefined (setting 'id')"

My model looks like this: export class SelectedApplicationFeatures { id: number; } In my TypeScript file, I imported the model as shown below: import { SelectedApplicationFeatures } from "src/app/models/selectedApplicationFeatures.model"; selec ...

Having trouble with Angular 6 and the @input directive not functioning correctly?

I created a basic Angular application to understand how @input works for component communication, but I am facing an issue where the value is not getting passed. I have gone through various forums where others had similar problems, but none of the suggeste ...

Guide on incorporating an external JavaScript library into an Angular component for testing purposes

Encountering an issue with a component that utilizes an external JavaScript library called Leader-Line. Every time I attempt to test this component, an error is thrown indicating that the function from the external library is not defined. component file ...

Triggering a class in Angular when another class is activated through JavaScript

My goal is to apply the class "xyz" when the class "xy" is activated using ngClass. I am looking to achieve the following scenario: If the class "xyz" is present in the tag, then activate the class "xy" Using ngClass="'xyz', 'xy'" ...

Tips for retrieving an item from a (dropdown) menu in Angular

I am facing an issue with selecting objects from a dropdown list. The array called "devices" stores a list of Bluetooth devices. Here is the HTML code: <select (change)="selectDevice($event.target.data)"> <option>Select ...

What is the proper way to mention JavaScript packages when including them as parameters in Angular elements within HTML?

I was looking to enhance the command to be more authoritative. <div (click)="lastCall(999)">click me</div> My attempt to utilize Number.MAX_SAFE_INTEGER resulted in an error from my computer stating that it wasn't recognized. As a result ...

Angular: When making an HTTP GET request, receiving an OPTIONS 405 error message indicating that the method is

I'm facing an issue with my API when making an HTTP GET request - it returns OPTIONS 405 (Method Not Allowed). Access to XMLHttpRequest at 'apiurl' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to ...

What steps can be taken to resolve the error message "How can you repair 'Cannot read properties of undefined (reading 'front_default')'?"

I'm encountering an issue while trying to display data from an API. Although I am able to access the data, a perplexing error keeps popping up that I can't seem to troubleshoot. Here's the error message: Uncaught TypeError: Cannot read pr ...

Encountering a 'scheduler flush execution error' and an Uncaught TypeError due to VueJS and Axios integration

After carefully examining my code, I have pinpointed the cause of this error to the following line: treeNodes.value = documentStore.convertToTree((await axios.get('/File')).data); Initially, I receive a warning: Vue warn]: Unhandled error during ...

Steps for sending a POST request for every file in the given array

I am working on an angular component that contains an array of drag'n'dropped files. My goal is to make a POST request to http://some.url for each file in the array. Here is what I have been attempting: drop.component.ts public drop(event) { ...

Using useRef as a prop in React with TypeScript

I am currently experimenting with TypeScript and encountering an issue when trying to use useRef in a custom element specifically when passing it as a prop I have attempted the following: import React from "react"; export interface InputProps extends ...

New post: "Exploring the latest features in Angular

Looking for help with integrating Angular and SpringREST to fetch data from the backend? Here's my situation: I need to retrieve a JSON string from the backend using a POST request, send it to my site's hosted link, and display it on the user int ...

The styles from bootstrap.css are not displaying in the browser

Currently in the process of setting up my angular 2 project alongside gulp by following this helpful tutorial: I've added bootstrap to the package.json, but unfortunately, it's not reflecting in the browser. I can see it in the node_modules and ...

What is the significance of the any type in Typescript?

As I delve into learning Typescript, a question arises in my mind. I find myself pondering the purpose of the any type. It seems redundant to specify it when every variable essentially acts as an "any" type by default. Consider this scenario where the out ...

problem with arranging sequences in angular highcharts

I am facing an issue with sorting points in different series using highcharts. To illustrate my problem, consider the following example series: [ {name: 'series one', value: 5 values}, {name: 'series two', value: 10 values} ] When usin ...

Display a modal dialogue with an image on the initial page load for each user

Working on a project with Angular 11, Angular material, and Bootstrap, I encountered an issue. I want to display a popup ad the first time a user visits the home page. The modal dialog is created using Angular material, and I have it in the ads component, ...

Is foreach not iterating through the elements properly?

In my code, I have a loop on rxDetails that is supposed to add a new field payAmount if any rxNumber matches with the data. However, when I run the forEach loop as shown below, it always misses the rxNumber 15131503 in the return. I'm not sure what I ...

How can I implement a bootbox alert in Typescript/Angular2?

Trying to incorporate Bootbox into my Angular2 project has proven to be a challenge. Despite extensive searching, I have been unable to find a satisfactory solution. I experimented with using angular2-modal as an alternative, but encountered numerous ...

Error TS2307: Module '~express/lib/express' could not be located

Currently, I am in the process of converting a fully functional JavaScript file to TypeScript. Since I am using Express in this particular file, I made sure to include the following at the beginning of the file: ///<reference path="./typings/globals/n ...