Exploring Typescript - Managing generic data types while preserving runtime type details

My situation involves a generic container type that can hold various types of data. The data's type is determined at runtime by a "type" field that contains a string:

type Type = "Numeric" | "Text";

type DataTypeFor<T extends Type> =
    T extends "Numeric" ? number
    : T extends "Text" ? string
    : never;

interface Container<T extends Type> {
    type: T;
    data: DataTypeFor<T>;
}

But, there seems to be an issue with the type inference for the data field when operating on an instance of this interface:

function operate<T extends Type>(container: Container<T>) {
    switch (container.type) {
        case "Numeric":
            // Error
            const a: number = container.data;
            console.log(a);
            break;
        case "Text":
            // Error
            const b: string = container.data;
            console.log(b);
            break;
        case "Fsasefsef":
            // No error here! Why?
            break;
    }
}

I seem to have a misunderstanding about how type inference works with generics in scenarios like these.

Is there a way to achieve the desired pattern in this context?

Typescript playground

Answer №1

To implement this structure, you can utilize Discriminated Unions. https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions

Here's an example:

interface Numeric {
    type: "Numeric"
    data: number
}

interface Text {
    type: "Text"
    data: string
}

type Container = Numeric | Text

function operate(container: Container) {
    switch (container.type) {
        case "Numeric":
            const numValue: number = container.data;
            console.log(numValue);
            break;
        case "Text":
            const textValue: string = container.data;
            console.log(textValue);
            break;
    }
}

Link to the TypeScript playground for testing.

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

Establish a route nickname for files outside the project directory

I'm currently tackling a project that is divided into multiple angular projects. Within these projects, there are some services that are shared. Is there a way for me to incorporate these services into my project without encountering errors? /root / ...

Challenges in integrating a PrimeNG Angular2 component with DynamicDialogRef, as well as the difficulties encountered when attempting to do

I am currently working on implementing a component that utilizes dynamic dialog and requires a direct usage. In the DynamicDialog example, there is a constructor in the car demo list component. constructor(private carService: CarService, public ref: Dynami ...

The upcoming construction of 'pages/404' page will not permit the use of getInitialProps or getServerSideProps, however, these methods are not already implemented in my code

Despite my efforts to search for a solution, I have not found anyone facing the same issue as me. When I execute next build, an error occurs stating that I cannot use getInitalProps/getServerSideProps, even though these methods are not used in my 404.tsx f ...

The error page is requesting a root-layout, which indicates that having multiple root layouts is not feasible

My issue is as follows: The not-found page located in my app directory requires a root-layout which I have added to the same directory. However, this setup prevents me from using multiple root layouts in the structure below. How can I resolve this? It see ...

Unleashing the Potential of TypeScript Union Types

My code consists of a union type called PromptOptions: type PromptOptions = | BasePromptOptions | BooleanPromptOptions | StringPromptOptions type BasePromptOptions = { kind: string | (() => string) }; type BooleanPromptOptions = { kind: ' ...

Encountering a Runtime Exception while setting up a Client Component in the latest version of Next JS (v13.3

I am facing an issue with a component in my Next JS website. When I attempt to convert it into a Client Component, the page fails to load in the browser and I encounter the following unhandled runtime exception: SyntaxError: "undefined" is not va ...

Filtering tables with checkboxes using Next.js and TypeScript

I've recently delved into Typescript and encountered a roadblock. While I successfully tackled the issue in JavaScript, transitioning to Typescript has left me feeling lost. My dilemma revolves around fetching data from an API and populating a table u ...

Submit a pdf file created with html2pdf to an S3 bucket using form data

Currently, I have the following script: exportPDF(id) { const options = { filename: 'INV' + id + '.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, dpi: 300, letterRendering: true, useC ...

Unable to correctly import a TypeScript class into a React project

I have encountered an issue where I am unable to assign a default value to a TypeScript Class in my React Project (Docusaurus). It works with: class Test { private hello: string; constructor() { this.hello = "hi"; } } However, it does ...

What is the process for obtaining the complete URL using the getDownloadURL() function along with a token?

An error occurred due to an unresolved FirebaseStorageError: "storage/object-not-found". The message indicates that the object 'k91a73uzb99' does not exist in Firebase Storage. This type of error is categorized under FirebaseError with a code of ...

Angular 7 Forms: Implementing Conditional "Required" Validation with Reactive Forms

Before I get into it, I won't be able to share the actual code I'm working on due to confidentiality reasons. However, I can provide a simplified version of the code... I am working with Angular 7 and Reactive Forms. In my form, I have a radio b ...

Ways to integrate user input into the header of an Angular HTTP post method

I need help figuring out how to incorporate user input into the header of a post method I am working with. I understand that some kind of binding is necessary, but I'm struggling to implement it in this case. Currently, I have a variable called postDa ...

"Angular allows for the reappearance of an alert even after it has been dismissed

Currently, I am engaged in an Angular project where I am implementing a feature to add objects to a table. However, not all of the object's fields are considered valid, and I need to notify the user through alerts. I am facing an issue where, after di ...

What could be the reason for the lack of impact when assigning a [dateClass] in mat-calendar?

I've been trying to customize the appearance of specific days in the mat-calendar component from Angular Material, but I'm having trouble getting it to work. I discovered the dateClass property which seemed like the right solution, but no matter ...

Utilize Knex to retrieve data from the req.query

express and knex have been giving me some trouble; I am struggling to get this endpoint working using req.querys (response from express), even though it worked fine when I used req.params. Express: app.get(`/actor`, async (req: Request, res: Response) =&g ...

Transferring functionality from a child component to a parent component

I have a Base Component called ListComponent and a ParentComponent named Businesses2ListComponent. The concept is to have multiple types of Lists with tables that all stem from the ListComponent. This requires passing the correct service accordingly. In t ...

Error loading personalized SVG on mat-icon

I have been attempting to load a custom SVG using the MatIconRegistry within my component. Here is the code snippet I am trying: constructor(fb: FormBuilder, private matIconRegistry: MatIconRegistry, private domSanitizer: DomSanitizer) { thi ...

Oops! The program encountered an issue where it was unable to access the properties of an undefined variable, specifically while trying to

When creating a custom validation function in Angular, I encountered an issue where using a variable within the validation would result in an error: "ERROR TypeError: Cannot read properties of undefined (reading 'file')". This occurred when chang ...

refresh the React component without having to refresh the entire webpage

Hey there, I have a component with a function called "handleAvatarUpload". Currently, when there is a change, the entire page reloads instead of just the component. Is there a way to reload only the component without refreshing the whole page? import { us ...

A novel way to enhance a class: a decorator that incorporates the “identify” class method, enabling the retrieval

I have been given the task to implement a class decorator that adds an "identify" class method. This method should return the class name along with the information passed in the decorator. Let me provide you with an example: typescript @identity(' ...