Is it essential to include both the generic type and argument in this TypeScript code?

To better understand the concept, please refer to this code snippet:

type Type1 = { num1: number; str1: string };
type Type2 = { num2: number; str2: string };
type Type3 = { num3: number; str3: string };
type Type4 = { num4: number; str4: string };

enum MyEnum {
  ONE,
  TWO,
  THREE,
  FOUR,
}

type MyTypes<T> = T extends MyEnum.ONE
  ? Type1
  : T extends MyEnum.TWO
  ? Type2
  : T extends MyEnum.THREE
  ? Type3
  : T extends MyEnum.FOUR
  ? Type4
  : never;

const urls = {
  [MyEnum.ONE]: 'http://one.com',
  [MyEnum.TWO]: 'http://two.com',
  [MyEnum.THREE]: 'http://three.com',
  [MyEnum.FOUR]: 'http://four.com',
};

const fetchData = (_url: string): unknown => ({
  // ...
});

export const myFun = <T extends MyEnum>(type: T) => {
  const data = fetchData(urls[type]);
  return { data: data as MyTypes<T> };
};

const one = myFun<MyEnum.ONE>(MyEnum.ONE);
const two = myFun<MyEnum.TWO>(MyEnum.TWO);
const three = myFun<MyEnum.THREE>(MyEnum.THREE);
const four = myFun<MyEnum.FOUR>(MyEnum.FOUR);

myFun() accepts the type twice:

  • As a generic type for static typing of the returned data.
  • As an argument used at runtime for selecting the correct url.

This method is effective, but I am seeking a way to simplify it by passing the type only once in either of these formats:

const a = myFun<MyEnum.ONE>();  // Option 1
const b = myFun(MyEnum.ONE);    // Option 2

Is there a solution for this?

I have attempted:

  • Option 1 (using generics only), but it lacks the capability to select the appropriate url dynamically.
  • Option 2 (using the argument only) like
    const myFun = (type: MyEnum) => {...}
    , but then I struggle to assign the correct type to the returned data.

Note: I am open to any suggestions on simplifying this process. The current definition of MyTypes<T> is cumbersome to me, so any alternative approach would be greatly appreciated.

Answer №1

Special thanks to @Samantha R. for enlightening me on the fact that TypeScript automatically infers the generic type when calling a function, eliminating the need to explicitly provide it. This means we can define myFunc() in the following way:

export const myFunc = <T extends EnumType>(type: T) => {
  const data = // ...
  return { data: data as Type<T> };
};

And you can simply use it like this:

const { data } = myFunc(EnumType.ONE);

TypeScript will intelligently deduce the type of data based on the generic provided and the argument passed (which is the same type specified by the generic). How awesome is that!

 argument ------> generic --------> data
(provided)       (deduced)      (deduced)

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

Angular: Validation triggered following ngModelChange event

I am dealing with an input field that has a customValidator called fooValidator. This custom validator checks if the input matches a specific regular expression: <form #contratForm="ngForm"> <input type="text" ...

The switchMap operator in RXJS v6.4 will output an Observable instead of the final result, as indicated by the TypeScript linter

I encountered an error while running my Angular 8 app. It seems to be related to a potential bug in RxJS or maybe I am overlooking something. import { of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; of(1,2,3) .pipe( ...

`Database Schema Enforcement in Firestore: Custom Objects vs Security Rules`

Firestore, being a noSQL database, is schemaless. However, I want to ensure that the correct data type is being passed in. Custom Objects As per Firebase documentation, https://firebase.google.com/docs/firestore/manage-data/add-data class City { const ...

Developing a collection of components with customizable color variations using React

I am interested in creating a React component library where users can specify color variants. For instance, I want to use the following syntax: const customTheme = createCustomTheme({ button: { variants: { primary: 'primary ...

Angular AutoComplete feature does not accurately filter the list items

I need to implement an auto-complete feature for the county field due to a large number of items in the list causing inconvenience to users who have to scroll extensively. Currently, there are two issues with the code. The first problem is that although t ...

What is the solution to toggling the openAll() or closeAll() functionality for an Angular Material expansion panel button?

Is there a way for me to toggle between two buttons: OpenAll and CloseAll? Can I determine the state of mat-accordion, whether it is fully opened or closed, using a boolean value? <div class="row"> <mat-icon *ngIf="accordion.op ...

How to display specific JSON objects that meet particular criteria in HTML cards using Ionic and Angular?

As a beginner in Ionic/Angular, I am attempting to fetch data from a JSON file and display it using cards in the HTML. The JSON contains numerous objects that are either marked as "deTurno == true" or "deTurno == false". Here is what I have so far: publi ...

When trying to access a property in Typescript that may not exist on the object

Imagine having some data in JS like this example const obj = { // 'c' property should never be present a: 1, b: 2, } const keys = ['a', 'b', 'c'] // always contains 'a', 'b', or 'c' ...

What steps should I take to maximize the efficiency of my angular function?

Hey there, I could really use some assistance with optimizing this code snippet. Does anyone have any ideas on how to improve it? Here's the code: optimizeCode(value, fieldName: string) { if (fieldName === 'fullName') { this.billingFields. ...

What is the method for retrieving the name of an object's property within an Angular template

I am trying to display the name of a nested object's property using Angular interpolation <ng-container ngFor="let item of saleDetailsAggegater.productMap | keyvalue"> <tr *ngFor="let qtyMap of item.value | keyvalue"&g ...

Using Vue 2 with a personalized Axios setup, integrating Vuex, and incorporating Typescript for a robust

I'm still getting the hang of Typescript, but I'm facing some challenges with it when using Vuex/Axios. Current setup includes: Vue CLI app, Vue 2, Vuex 3, Axios, Typescript At a high level, I have a custom Axios instance where I configure the ...

The issue with Vuex and Typescript is that when using mutation object payloads, they are consistently undefined

Every time I run my code, the object payload I'm passing as a secondary parameter to my Vuex mutation method ends up being undefined. Both my Vuex and component files are coded in TypeScript. When looking at my index.ts file for my Vuex store (where ...

Encountering authorization issues while using CASL in conjunction with PrismaORM, NestJs, and Typescript results in an

Within a middleware, I am implementing a condition to grant access to users who reside in the same apartment as the authenticated user. The condition is as follows: can(DirectoryAction.VIEW, 'DirectoryUser', { roles: { some: { role: { unitId: CAS ...

Definition file for Typescript d.ts that includes optional properties in a function

Within my code, I have a function that offers different results based on specified options. These options dictate the type of return value. The function is currently written in plain JavaScript and I am looking to provide it with types using an index.d.ts ...

I'm puzzled by the error message stating that '<MODULE>' is declared locally but not exported

I am currently working with a TypeScript file that exports a function for sending emails using AWS SES. //ses.tsx let sendEmail = (args: sendmailParamsType) => { let params = { //here I retrieve the parameters from args and proceed to send the e ...

Unable to perform module augmentation in TypeScript

Following the guidelines provided, I successfully added proper typings to my react-i18next setup. The instructions can be found at: However, upon creating the react-i18next.d.ts file, I encountered errors concerning unexported members within the react-i18 ...

Material-UI chart displays only loading lines upon hovering

Currently, I am utilizing a Material UI Line chart in my NextJS 14 application to showcase some data. Although the data is being displayed properly, I have encountered an issue where the lines on the chart only render when hovered over, rather than appeari ...

Acquiring the class function from a service which yields a model

Within my class called userName, I have defined properties that form a model when casting from json. Additionally, this class includes a simple function that returns the full Name: export class userName { firstName: string; lastName: string; g ...

Avoid accessing members in Vue 3 using TypeScript that may be unsafe

Recently, we initiated the process of upgrading from Quasar v1 to Quasar v2 (moving from Vue 2 to Vue 3). In the past, this code functioned without any issues: // src/pages/myComponent.vue <script lang="ts"> import { defineComponent } from ...

Leveraging Enums in Angular 8 HTML template for conditional rendering with *ngIf

Is there a way to implement Enums in an Angular 8 template? component.ts import { Component } from '@angular/core'; import { SomeEnum } from './global'; @Component({ selector: 'my-app', templateUrl: './app.componen ...