What is the method for deducing the return type based on the parameter type in a generic function?

Check out this code snippet featuring conditional types:

class X {
    public x: number;
}

class Y {
    public y: number;
}

type DataCategory = "x" | "y";

type TData<T extends DataCategory> =
    T extends "x" ? X :
    T extends "y" ? Y :
    never;

I'm trying to link a function parameter with its return type using conditional types. However, my attempts have been unsuccessful so far:

function RetrieveData<T extends DataCategory>(category: T): TData<T> {
    if (category == "x")
        return new X();
    else if (category == "y")
        return new Y();
}

What is the correct syntax for achieving this? Is it feasible in TypeScript 2.8?

Update

There's an ongoing issue on GitHub that addresses a similar example. At the moment, the answer seems to be "No, but there might be potential in the future."

Answer №1

One way to handle different data types is by using function overloads like in the following example:

function RetrieveData(dataType: "x"): X;
function RetrieveData(dataType: "y"): Y;
function RetrieveData(dataType: DataType): X | Y {
    if (dataType === "x")
        return new X();
    else if (dataType === "y")
        return new Y();
}

const resultX = RetrieveData('x');  // Result inferred as type X
const resultY = RetrieveData('y');  // Result inferred as type Y

Answer №2

Using the ternary operator with generic types can be a bit tricky:

type TriviallyA<T extends DataType> = 
      T extends any ? A : A;
function GetData<T extends 'a' = 'a'>(dataType: T): TriviallyA<T> {
    return new A(); // Error: Type 'A' is not assignable to type 'TriviallyA<T>'
}

On the other hand, generics work well with attribute lookup. You can create an interface to map strings to specific types and then use keyof along with attribute lookup to achieve similar functionality as TData:

interface DataTypeMapping {
    a: A;
    b: B;
}
type DataType = keyof DataTypeMapping;
type TData<T extends DataType> = DataTypeMapping[T];

function GetData<T extends DataType>(dataType: T): TData<T> {
    // With this setup, the expected return type is either A or B, making this valid!
    if (dataType === 'a') {
        return new A(); 
    } else if (dataType === 'b') {
        return new B();
    }
}

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

How to retrieve a value from an Angular form control in an HTML file

I have a button that toggles between map view and list view <ion-content> <ion-segment #viewController (ionChange)="changeViewState($event)"> <ion-segment-button value="map"> <ion-label>Map</ion-label> & ...

Display a separate component within a primary component upon clicking a button

Looking to display data from a placeholder module upon component click. As a beginner with React, my attempts have been unsuccessful so far. I have a component that lists some information for each element in the module as a list, and I would like to be ab ...

Execute different commands based on operating system using NPM conditional script for Windows and Mac

Scenario: I am currently configuring a prepublishOnly hook in NPM. This hook is designed to remove the "lib" folder, transpile the typescript source files into a new lib folder, and then execute the tests. The issue at hand: There are two individuals re ...

What is the process for extracting the "path expression" from an interface in TypeScript?

My goal is to achieve the following structure: type Post = { id: number title: string author: { name: string } comments: { text: string }[] } type ExtractPathExpressions<T> = ??? type Paths = ExtractPathExpressions<Post> / ...

Aliases for NPM packages and TypeScript declaration files

I am in need of two separate versions of a package, and fortunately with npm 6.9.0 I can easily accomplish that now. My dilemma is this: the package comes with type definitions. However, when I create an alias for this package and refer to it using the al ...

How can I prevent the enter key from working with Twitter Typeahead?

Is there a way to prevent the enter key from being pressed on an element within Twitter Typeahead's dropdown feature while using Angular with Typescript? I attempted to utilize preventDefault() when event.keycode === 13 on the ng-keydown event for th ...

Encountering a TypeScript error in MUI 5 when attempting to spread values in props

I am encountering an issue with a typescript error related to the MUI sx prop. The problem arises when I attempt to merge or spread multiple sx values into an sx prop, resulting in an error. It seems to work fine if only one item is present in the sx prop, ...

Angular functions are executed twice upon being invoked within the html file

I decided to kick-start an Angular project, and I began by creating a simple component. However, I encountered a perplexing issue. Every time I call a function in the HTML file from the TypeScript file, it runs twice. TS: import { Component, OnInit } from ...

How can you define a function type for a rest parameter in Typescript?

At this point, I have a function that takes in two parameters: param 'a' as a string and 'b' as a function that returns a string. My intention is to call it using a rest parameter and specify the types accordingly. However, on line 10 ...

Undefined TypeScript Interface

Here's my situation: public retrieveConnections() : IUser[] { let connections: IUser[]; connections[0].Id = "test"; connections[0].Email = "asdasd"; return connections; } I know this might be a dumb question, but why is connecti ...

Using regular expressions, you can locate and replace the second-to-last instance of a dot character in an email address

I'm looking to replace the second last occurrence of a character in a given string. The length of the strings may vary but the delimiter is always the same. Here are some examples along with my attempted solutions: Input 1: james.sam.uri.stackoverflo ...

The Environment variable in React Native is not functioning when utilizing TypeScript

After installing the react-native-dotenv library, I followed the instructions outlined in the TypeScript guide. I then created a .env file with the following contents: MARVEL_API = <url> MARVEL_PUBLIC_KEY = <public-key> MARVEL_PRIVATE_KEY = &l ...

Issue with Angular 6 Share module functionality not functioning as expected

While creating my Angular 6 application, I encountered an issue with sharing a header across multiple pages. I tried including it but it doesn't seem to be working. Can anyone point out what I might be doing wrong? For a demonstration, you can visit . ...

Does the router navigate function instantly update the router URL?

I'm testing whether the navigate function will immediately alter the router URL upon execution. this.router.navigate(['/home/products']); if (this.router.url.includes('/home/products')) console.log('URL has been changed&apos ...

Unable to perform a union operation that combines multiple enums into one

Here is a basic example: export enum EnumA { A = 'a', } export enum EnumB { A = 'b', } export class SomeEntity { id: string; type: EnumA | EnumB; } const foo = (seArray: SomeEntity[]) => { seArray.forEach((se) => { ...

What is the best way to send {...rest} properties to a text field in react material?

When using a material textfield inside a wrapper component and passing the remaining props as {...otherprops} in a JavaScript file, everything works fine. However, when attempting to do the same in TypeScript, an error occurs. const TextFieldWrapper = (pro ...

Implementing recursive functionality in a React component responsible for rendering a dynamic form

Hello to all members of the Stack Overflow community! Presently, I am in the process of creating a dynamic form that adapts based on the object provided, and it seems to handle various scenarios effectively. However, when dealing with a nested objec ...

Leveraging an AngularJS service within Angular framework

I am trying to incorporate an AngularJS service into my Angular project. Below is my main.ts file: import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {AppModule} from './app/app.module'; import {UpgradeMo ...

Choosing several buttons in typescript is a skill that every programmer must possess

I need help with selecting multiple buttons in TypeScript. The code I tried doesn't seem to be working, so how can I achieve this? var input = document.getElementById('input'); var result = document.getElementById('result'); v ...

Angular's change detection is currently inactive

I need to toggle the visibility of a button based on the value of a boolean variable using the Output property. However, I am facing an issue where the button remains hidden even after the variable is updated with a true value. Parent Component.ts showE ...