Using a Typescript-specific type within a switch case statement

I'm currently working on a function that, when given an enum value, should return a specific type. I am facing an issue where Typescript does not seem to recognize the properties inside switch and if statements.

interface X {
  x: string;
}

interface Y {
  y: string;
}

enum DataType {
  x = 'x',
  y = 'y',
}

interface Type {
  [DataType.x]: X;
  [DataType.y]: Y;
}

function customFunction<T extends keyof Type>(type: T): Type[T] {
  switch (type) {
    case DataType.x:
      return {x: 'example'}; // <--- Although there's no error, TS fails to recognize the property
  }
}

Developed with Typescript version 4.2.3.

Answer №1

Perhaps you may find function overloads to be a suitable solution. Should you opt for this approach, you will have to substitute interface Type with a specific overload signature for each scenario.

interface A {
  a: string;
}

interface B {
  b: string;
}

enum DataType {
  a = 'a',
  b = 'b',
}

function test(value: DataType.a): A;
function test(value: DataType.b): B; 
function test(value: DataType): A | B {
  switch (value) {
    case DataType.a:
      return {a: 'testA'};
    case DataType.b:
      return {b: 'testB'};
  }
}

TypeScript playground - live example

Answer №2

It appears that using a switch statement may not be the ideal approach due to typescript limitations, but there is an alternative solution available.

interface A {
  a: string;
}

interface B {
  b: string;
}

enum DataType {
  a = "a",
  b = "b",
}

interface Type {
  [DataType.a]: A;
  [DataType.b]: B;
}

function test<T extends keyof Type>(type: T): Type[T] {
  return (type === DataType.a ? { a: "test" } : { b: "test" }) as Type[T];
}

Answer №3

When dealing with a set of related Types where differentiation is crucial, it is recommended to use a dedicated property for this purpose - TypeScript is designed for optimal performance in such scenarios. For instance:

type KindValues = "a" | "b"

type TT = {
  kind:KindValues,
  body: any
}

type TA = {
  kind:"a",
  body:string
}
function isTA(t:TT):t is TA { return t.kind==="a"; }

type TB = {
  kind:"b",
  body:number
}
function isTB(t:TT):t is TB { return t.kind==="b"; }

function handler(t:TT):void{
  if (isTA(t)){
    //t.body=1  // error: number is not assignable to string
    t.body = 'x';
  }
  else if (isTB(t)){
    //t.body='x'  // error: string is not assignable to number
    t.body = 1;
  }
}

To avoid excessive type checks, it is often more versatile to establish a Map linking kind to corresponding functions.

While TypeScript does not mandate a single discriminator key, it performs efficiently even with an additional key for subtyping types. However, keeping the keys minimal enhances auto-completion capabilities.

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

When attempting to declare a functional component in React utilizing styled-components in TypeScript, an error is encountered stating "No overload matches this call."

Playground https://codesandbox.io/s/typescript-type-checking-question-0b42t Sample Code type BadgeTypes = { success: string; secondary: string; alert: string; text: string; }; type Theme = { fonts?: object; borderRadius: string; primary?: o ...

Changing the color of a specific span using Angular

I am working with a dynamic mat-table where columns are added and populated on the fly. The table headers are styled using divs and spans. My goal is to change the color of a header to black when clicked, but also un-toggle any previously selected header. ...

I'm experiencing some difficulties utilizing the return value from a function in Typescript

I am looking for a way to iterate through an array to check if a node has child nodes and whether it is compatible with the user's role. My initial idea was to use "for (let entry of someArray)" to access each node value in the array. However, the "s ...

Exploring the parent-child relationship of three components within Angular 2

Currently, I am developing a shopping cart using Angular 2. The application consists of two components - one for categories and another for product listings, both included in the main app component as children. However, I'm facing an issue where these ...

Learn how to import from a .storybook.ts file in Vue with TypeScript and Storybook, including how to manage Webpack configurations

I'm currently utilizing Vue with TypeScript in Storybook. Unfortunately, there are no official TypeScript configurations available for using Vue with Storybook. How can I set up Webpack so that I am able to import from another .storybook.ts file with ...

When assigning JSON to a class object, the local functions within the class became damaged

This is a demonstration of Object Oriented Programming in JavaScript where we have a parent Class called Book with a child class named PriceDetails. export class Book { name: String; author: String; series: String; priceDetails: Array<Price> ...

Having trouble getting the onClick function to work in your Next.js/React component?

Recently, I delved into using next-auth for the first time and encountered an issue where my login and logout buttons' onClick functions stopped working when I resumed work on my project the next day. Strangely, nothing is being logged to the console. ...

SystemJS TypeScript Project

I am embarking on a journey to initiate a new TypeScript project. My aim is to keep it simple and lightweight without unnecessary complexities, while ensuring the following: - Utilize npm - Implement TypeScript - Include import statements like: import ...

When employing the caret symbol (^) in package.json, it fails to update the minor version

Within my package.json file, there is a line that reads as follows: "typescript": "^4.1.6", The presence of the caret (^) symbol indicates that npm should install a version of TypeScript above 4.1 if available. However, upon checking ...

Display <video> component using Angular 2

When attempting to display videos sourced from an API link, I encountered a problem where only the player was visible without the actual video content. The navigation controls of the player were also unresponsive. Interestingly, when manually inputting the ...

The npm package has been successfully installed, but VS Code is having trouble locating it

Currently, I am in the process of developing a simple npm package known as type-exception using TypeScript. After successful test runs and publication on NPM, I have been able to install it into another project (project B). However, upon importing it as a ...

Is there a way to incorporate a dropdown feature into a search bar using Ant Design?

I'm currently working on a project that requires me to incorporate two drop-down menus inside the search box. Despite following the guidelines provided in the documentation (https://ant.design/components/input), I encountered a problem when trying to ...

Step-by-step guide on setting up pnpm directly, without the need to first

Here I am, faced with a brand new Windows 10 installation - only VS Code is installed and nothing more: Can pnpm be installed and used without the need for npm? Is this action beneficial or detrimental? Consideration: typescript ...

Define a new type in Typescript that is equal to another type, but with the added flexibility of having optional

I have 2 categories: category Main = { x: boolean; y: number; z: string } category MainOptions = { x?: boolean; y?: number; z?: string; } In this scenario, MainOptions is designed to include some, none, or all of the attributes that belong to ...

Omit functions from category

This question reminds me of another question I came across, but it's not quite the same and I'm still struggling to figure it out. Basically, I need to duplicate a data structure but remove all the methods from it. interface XYZ { x: number; ...

Error encountered: The import of 'createLocation' from 'history' failed. This issue occurred due to conflicting versions of History and React-Router-DOM

While attempting to configure an existing project on a new development server, I encountered the following error: ./node_modules/react-router-dom/esm/react-router-dom.js Attempted import error: 'createLocation' is not exported from 'histor ...

Displaying user input data in a separate component post form submission within Angular

I recently developed an employee center app with both form and details views. After submitting the form, the data entered should be displayed in the details view. To facilitate this data transfer, I created an EmployeeService to connect the form and detail ...

Trying to determine the specific key of an object based on its value in TypeScript?

Looking to create a function that can retrieve the key for a given value. type Items<T> = Exclude<{ [P in keyof T]: [P, T[P]]; }[keyof T], undefined>[]; export const getKeyName = <T extends Record<PropertyKey, unknown>, V>( col ...

Encountering a problem with Vue StripeCheckout while navigating to a different component

I'm looking to integrate the StripeCheckout component into my Vue application. After copying and updating their example code using the composition API from here, everything works fine when I route to the subscribe component. However, if I try to navig ...

Typescript - A guide on updating the value of a key in a Map object

My Map is designed to store Lectures as keys and Arrays of Todos as values. lecturesWithTodos: Map<Lecture, Todos[]> = new Map<Lecture, Todos[]>(); Initially, I set the key in the Map without any value since I will add the Todos later. student ...