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

Replace Formik with useFormik to streamline your code

I have implemented Formik/Yup for validation on a page that triggers a GraphQL mutation. The code is functioning as expected: export default function RemoveUserPage() { const [isSubmitted, setIsSubmitted] = useState(false); const [isRemoved ,setIsRemo ...

Service function in Angular 2 is returning an undefined value

There are two services in my project, namely AuthService and AuthRedirectService. The AuthService utilizes the Http service to fetch simple data {"status": 4} from the server and then returns the status number by calling response.json().status. On the ot ...

Implementing a more efficient method for incorporating UUIDs into loggers

------------system1.ts user.on('dataReceived',function(data){ uniqueId=generateUniqueId(); system2.processData(uniqueId,data); }); ------System2.ts function processData(u ...

Issue with Angular 2 Observable not triggering the complete function

I've been experimenting with the hero app tutorial for Angular 2 and currently have this Component set up: import { Component, OnInit } from '@angular/core' import { Subject } from 'rxjs/Subject'; import { Hero } from "./hero"; im ...

The script type `(close: any) => Element` cannot be assigned to type `ReactNode`

Encountering a problem while adding a popup in my TypeScript code Error: Type '(close: any) => Element' is not compatible with type 'ReactNode'. <Popup trigger={ <button className="fixed bott ...

What are some ways to make autorun compatible with runInAction in mobx?

Currently delving into the world of mobx and runInAction, facing a challenge in comprehending why autorun fails to trigger my callback in this particular scenario: class ExampleClass { // constructor() { // this.exampleMethod(); // } ...

Utilizing Vue 3/Nuxt 3 Scoped Slots to Automatically Deduce Generic Data Types from Props

I am looking to incorporate a carousel component into Nuxt v3. The component will be passed an array of items, focusing solely on the logic without handling styling or structuring. Currently, this is what my component looks like: components/tdx/carousel. ...

Error! Unable to Inject ComponentFactoryResolver

Recently, I attempted to utilize ComponentFactoryResolver in order to generate dynamic Angular components. Below is the code snippet where I am injecting ComponentFactoryResolver. import { Component, ComponentFactoryResolver, OnInit, ViewChild } from "@an ...

Is there a way to dynamically create a property and assign a value to it on the fly?

When retrieving data from my API, I receive two arrays - one comprising column names and the other containing corresponding data. In order to utilize ag-grid effectively, it is necessary to map these columns to properties of a class. For instance, if ther ...

Error encountered while attempting to utilize 'load' in the fetch function of a layer

I've been exploring ways to implement some pre-update logic for a layer, and I believe the fetch method within the layer's props could be the key. Initially, my aim is to understand the default behavior before incorporating custom logic, but I&ap ...

Tips to successfully save and retrieve a state from storage

I've encountered a challenge while working on my Angular 14 and Ionic 6 app. I want to implement a "Welcome" screen that only appears the first time a user opens the app, and never again after that. I'm struggling to figure out how to save the s ...

I am having trouble locating the name 'React' within the function variable when using Typescript with generic arguments

Is there a way to store a typescript function with generic arguments in a variable? function identity<T>(arg: T): T { return arg; } I attempted to do it like this but got an error message saying Cannot find name 'React' const identity = ...

Deep Dive into TypeScript String Literal Types

Trying to find a solution for implementing TSDocs with a string literal type declaration in TypeScript. For instance: type InputType = /** Comment should also appear for num1 */ 'num1' | /** Would like the TSDoc to be visible for num2 as well ...

Angular Karma Error - MatDialogRef Provider Not Found

While testing with Angular Karma, I encountered the following error... NullInjectorError: StaticInjectorError(DynamicTestModule)[ManageProblemsComponent -> MatDialogRef]: StaticInjectorError(Platform: core)[ManageProblemsComponent -> MatDialogRef]: ...

Updating nested interface values using React hooks

I am looking to develop an application that can seamlessly update a nested configuration file after it has been imported (similar to swagger). To achieve this, I first created a JSON configuration file and then generated corresponding interfaces using the ...

Tips for customizing Material UI's styled() SVG icon to accept SVG icon as a react component:

Currently, I have functioning code that uses the "any" type for props. When transitioning to MUI v5 and using the mui v4 makeStyles, this approach raises compatibility issues that were not present before. // Import SVG Icons components import { ReactCo ...

The element 'PROGRAM_ID' is not recognized within the 'import @metaplex-foundation/mpl-token-metadata' type

I am currently in the process of creating a token within the Solana network, but I've encountered a particular issue. I have successfully installed @metaplex-foundation/mpl-token-metadata and integrated it into my code; however, an error is persisting ...

TypeScript Color Definitions in React Native

I'm working on a component that requires users to pass only valid color values using TypeScript type checking in a React Native project. How can I achieve this and which types should I use? const TextBody = ({ color }: {color: //Need This}) => { ...

Learn how to transform an object into an array consisting of multiple objects in TypeScript

The car's details are stored as: var car = {model: 'Rav4', Brand: 'Tayota'} I need to convert this information to an array format like [{model: 'Rav4', Brand: 'Tayota'}] ...

Getting TypeScript errors when incorporating a variant into a Material-UI button using a custom component

I have created a unique Link component inspired by this particular example. Take a look at the code below: import classNames from 'classnames'; import {forwardRef} from 'react'; import MuiLink, {LinkProps as MuiLinkProps} from '@ma ...