Is there a method to accurately pinpoint the specific type?

Is there a way to optimize the validateField function to narrow down the type more effectively?

type TStringValidator = (v: string) => void;
type TNumberValidator = (v: number) => void;

type TFields = 'inn' | 'amount';

interface IValidators {
  inn: TStringValidator[];
  amount: TNumberValidator[];
}

const handleString: TStringValidator = (value: string) => {};
const handleNumber: TNumberValidator = (value: number) => {};

const validators = {
  inn: [handleString],
  amount: [handleNumber],
} satisfies IValidators;

function validateField(field: TFields, value: string | number) {
  const fieldValidators = validators[field];

  for (const validator of fieldValidators) {
    // The issue lies here
    const result = validator(value);
  }

  return;
}

Link to the TS playground.

Expect validator(value) call not to throw TS error:

Argument of type 'string | number' is not assignable to parameter of type 'never'.
  Type 'string' is not assignable to type 'never'.(2345)
(parameter) value: string | number

The TypeScript compiler seems to struggle with inferring the type for the dynamic validator based on the field value. Perhaps some refactoring of the validateField function could help.

Answer №1

To prevent the never type, you can establish a list of all approved types in the validator

type AllowedTypes = string & number;

then when calling the generic validator function, simply convert the variable to the allowed type

const result = validator(value as AllowedTypes);

here is a complete example

type TStringValidator = (v: string) => void;
type TNumberValidator = (v: number) => void;

type TFields = 'inn' | 'amount';
type AllowedTypes = string & number;

interface IValidators {
  inn: TStringValidator[];
  amount: TNumberValidator[];
}

const handleString: TStringValidator = (value: string) => {};
const handleNumber: TNumberValidator = (value: number) => {};

const validators = {
  inn: [handleString],
  amount: [handleNumber],
}
satisfies IValidators;

function validateField(field: TFields, value: string | number) {
  const fieldValidators: (TNumberValidator | TStringValidator)[] = validators[field];

  for (const validator of fieldValidators) {
    const result = validator(value as AllowedTypes);
  }

  return;

Answer №2

It seems that the issue lies in the uncertain type of your value, whether it is a string or number, and TypeScript is unable to determine the specific type validator being used within the loop (either TStringValidator or TNumberValidator). While the structure may be a tad awkward, you can still address the problem with the following approach:

function validateField(field: TFields, value: string | number) {
  const fieldValidators = validators[field];

  Object.keys(validators).forEach(key => {
    if (key === 'inn' && typeof value === 'string') {
      const result = validators[key][0](value)
    }
  })

  return;
}

There's always room for improvement in the code snippet provided above, but the concept should be clear.

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

Navigating the use of property annotations in Mapped Types with remapped keys

After exploring the concept of Key Remapping in TypeScript, as shown in this guide, I am wondering if there is a way to automatically inherit property annotations from the original Type? type Prefix<Type, str extends string> = { [Property in keyo ...

Implementing an All-Routes-Except-One CanActivate guard in Angular2

In order to group routes within a module, I am aware that it can be done like this: canActivate: [AuthGuard], children: [ { path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, ...

Creating a dynamic selection in Angular without duplicate values

How can I prevent repetition of values when creating a dynamic select based on an object fetched from a database? Below is the HTML code: <router-outlet></router-outlet> <hr> <div class="row"> <div class="col-xs-12"> & ...

Prevent accidental misuse of object[index] in Typescript

It caught me off guard when I discovered that TypeScript allows the following code: interface IFoo { bar: string; } const foo: IFoo = {bar: 'bar'}; console.log( foo['anything'] // I want TypeScript to stop this ); Is there a way ...

Parsing JSON objects with identifiers into TypeScript is a common task in web development

I possess a vast JSON object structured like so: { "item1": { "key1": "val1", "key2": "val2", "key3": [ "val4", "val5", ] }, { "item2": { "key1": "val1", "ke ...

Unable to retrieve the third attribute of a Class using Angular2's toString method

Here is the code snippet I am working with: import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Hello {{name}}</h1> <p><strong>Email:</strong> {{email}}< ...

Using Angular 8 for Filtering Firebase Data

I need to implement a filter on the titles of my stored data, but I am facing an issue where the structure of the filtered data changes. The original "key" of the data gets deleted by the filter and is replaced with an index instead. Link to repository : ...

defining data types based on specific conditions within an object {typescript}

Can someone help with implementing conditional function typing in an object? let obj = { function myfunc (input: string): number; function myfunc (input: number): string; myfunc: function (input: string|number):string|number { ... } } I've been ...

utilizing routerLinks to transfer data and trigger a specific function

I'm having trouble passing data through the routerLink and calling the function(). It doesn't seem to be working as expected. Here's an example of my code and you can view a working demo on StackBlitz. First Component(HTML) <span [route ...

Creating a countdown clock in Angular 5

I am currently working with Angular 5. Is there a way to initiate a timer as soon as the 'play' button is clicked, in order to track the elapsed time since the click? Additionally, I am interested in learning if it's feasible to pause the ...

The reason for duplicating the import of an NPM package in TypeScript (specifically for Firebase Functions)

I recently found this code snippet in the Firebase documentation: import * as functions from 'firebase-functions'; import * as admin from 'firebase-admin'; import 'firebase-functions'; admin.initializeApp(); I'm curious ...

Exploring FileReader in conjunction with React and Typescript

I am facing an issue while trying to upload a JSON file using an input element of type file. When I attempt to use the onload method on FileReader in TypeScript, I receive an error message saying "Cannot invoke an object which is possibly 'null'. ...

I'm having trouble understanding why I can't access the properties of a class within a function that has been passed to an Angular

Currently, I have integrated HTML 5 geolocation into an Angular component: ... export class AngularComponent { ... constructor(private db: DatabaseService) {} // this function is linked to an HTML button logCoords(message, ...

What is the best way to include a new property to an existing interface and then export the updated interface in Typescript?

Can you provide guidance on creating a new interface - UIInterface that combines SummaryInterface with additional properties? For example: import { SummaryInterface } from 'x-api'; // summaryInterface includes 20+ predefined properties generated ...

A guide to simulating Custom Dialog in Angular for Unit Testing with Jest

Currently, I am in the process of creating test cases for unit tests and ensuring code coverage for a method that triggers a dialog component when isEdit = 'true' which is retrieved from localStorage. The issue arises with the first test case wh ...

NestJS is having trouble importing generated types from the Prisma client

When working with Prisma in conjunction with NestJs, I encountered an issue after defining my model and generating it using npx prisma generate. Upon importing the generated type, I can easily infer its structure: import { FulfilmentReport, FulfilmentRepor ...

How do I select all checkboxes in TypeScript when I only click on one of them?

I'm currently working with a list of checkboxes in my HTML code: <div class="col-sm-12" *ngIf="ControllerModel"> <div *ngFor="let controller of ControllerModel" class="panel col-md-6 col-lg-6 col-xs-6"> <div class="panel-heading" ...

Create a global variable by importing an external module in TypeScript

I am currently developing a TypeScript npm module called https://www.npmjs.com/package/html2commonmark. This module is versatile and can be utilized in nodejs (via require) as well as in the browser (by loading node_modules/html2commonmark/dist/client/bund ...

Different results are being obtained when destructuring props in a component

Just diving into the world of React and trying to grasp destructuring. I've been doing some reading on it, but I'm currently stuck. When I try to destructure like this function MList({action}) { // const data = [action];}, I only get 'camera ...

Ensuring the inclusion of library licenses in the production build is a crucial step

We have numerous dependencies (node_modules) in our Angular app, which are typically licensed under Apache 2.0 or MIT. From my understanding of the licenses, the production build is considered a "derived work" and we are required to include copyright notic ...