Comparing potential type literals in Typescript

Consider the following example:

type BinaryOp = 'MOV'
type UnaryOp = 'ADD' | 'SUB' | 'JRO'
const BinaryOps: BinaryOp[] = ['MOV']
const UnaryOps: UnaryOp[] = ['ADD', 'SUB', 'JRO']

type Line =
    { op: BinaryOp, a: number, b: number }
  | { op: UnaryOp, a: number }

Now, let's look at the "pattern match" below:

switch (line.op) {
    case 'ADD':
    case 'SUB':
    case 'JRO':
        return `${line.op} ${line.a}`
    case 'MOV':
        return `${line.op} ${line.a}, ${line.b}`
}

I find it cumbersome that I have to list out all possible options in order for the cases to understand if the op is a UnaryOp or a BinaryOp. Is there a more concise way to handle this?

IMPORTANT. Keep in mind that this is just a simplified sample, and there may be different types of Op's in actual scenarios.

Answer №1

There doesn't seem to be any clever TypeScript techniques that can help avoid listing all the case labels, as they must represent values rather than types.

Nevertheless, you have the option of using if statements instead of a switch, and incorporating user-defined type guards within those if expressions.

A user-defined type guard refers to a function with a return type that serves as a type predicate. For instance, creating a user-defined type guard for a UnaryOp could resemble the following:

function isUnaryOp(op: string): op is UnaryOp {
  return op && UnaryOps.includes(op as any);
}

When applied in if statements, user-defined type guards will narrow down the type:

if (isUnaryOp(line.op)) {
  const op = line.op; // Inferred to be UnaryOp
} else if (isBinaryOp(line.op)) {
  const op = line.op; // Inferred to be BinaryOp
} else {
  const op = line.op; // Inferred to be never
}

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

The back button in the Chrome browser fails to trigger a page refresh within an Angular application

The code snippet above was used in an attempt to refresh the page when the back button is pressed, but it only works inconsistently in Chrome. The issue seems to be that despite correctly detecting the back button press, the page does not always refresh ...

Creating nested objects in Javascript involves adding an object inside another object

There are two objects that I have: obj1= { '201609': 52, '201610': 54, '201611': 56, metric: 'promotionsOut', careerLevelGroups: [ { '201609': 52, &a ...

Expanding the functionality of the Typescript number data type

I am trying to enhance the functionality of the number type. Here is the code I attempted: interface NumberExtension { IsInRange(min: number, max: number):boolean; } Number.prototype.IsInRange = function(min: number, max: number): boolean { if (( ...

Is there a way for me to access the data stored in session storage in Next.js?

One of the components in my project is a slider, which allows users to set the number of columns in an Image Gallery component. This code snippet shows the implementation of the slider component: export default function Slider({ value, handleChange }: ISl ...

Can you enforce function signatures on an existing library like rxjs using TypeScript?

My goal is to always include an error function when using rxjs's subscribe method. To achieve this, I am thinking of creating an interface by adding the following code snippet: Observable.prototype.sub = Observable.prototype.subscribe; By assigning ...

What is the process for discovering the kinds of models that can be generated with a Prisma client?

Ensuring data type correctness when creating a Prisma model named 'bid' is crucial. With auto-generated prisma types available, understanding the naming convention and selecting the appropriate type can be confusing. The bid schema looks like th ...

What is the best way to retrieve the dimensions of an Angular 5 Component prior to displaying it on the screen?

I am currently working on integrating a generic tooltip feature in Angular 5. In order to ensure proper positioning, especially centering relative to the target element, I need to obtain the width and height of the tooltip before it is rendered. While I h ...

What is the best way to navigate to a specific component's location on

In Angular, I am looking to scroll to the position of a specific component. The components are created based on the repeticiones variable. Below is my HTML code for reference:https://i.sstatic.net/FJ7Do.png Additionally, here is the TypeScript code associ ...

Restrictive discriminated union via function argument

I am in possession of a shop that organizes a variety of types based on their IDs interface Dog { type: "dog"; woofs: string; } interface Cat { type: "cat"; meows: string; } type Pet = Dog | Cat; type AnimalState = Record<string, Pet ...

Tips for isolating shared attributes within MUI Data Grid column configurations

Currently, I am developing a ReactJS Typescript Application using MUI as my component library. My goal is to create a comprehensive CRUD Datagrid similar to the MUI Datagrid component. In the example provided, many columns share common properties. To effic ...

Issue: Module 'typescript' not found in Ionic application

As a beginner in the world of Ionic framework, I encountered a problem while attempting to build my app using "ionic serve" - I received the error message "cannot find module 'typescript'". I believed I had resolved the issue by installing Ty ...

Refreshing Angular 9 component elements when data is updated

Currently, I am working with Angular 9 and facing an issue where the data of a menu item does not dynamically change when a user logs in. The problem arises because the menu loads along with the home page initially, causing the changes in data to not be re ...

Nextjs provides separate instances for middleware and api routes, even when using the same singleton class

Here is a utility function that acts as a singleton class to store a counter value. export class CounterSingleton { private static instance: CounterSingleton; private count: number; private constructor() { this.count = 0; } public static ge ...

Is it better to convert fields extracted from a JSON string to Date objects or moment.js instances when using Angular and moment.js together?

When working on editing a user profile, the API call returns the following data structure: export class User { username: string; email: string; creationTime: Date; birthDate: Date; } For validating and manipulating the birthDate val ...

Can the tooltip placement be adjusted in ng-bootstrap when it reaches a specific y-axis point?

Currently, I am facing an issue with my tooltip appearing under the header nav-bar instead of flipping to another placement like 'left-bottom' when it reaches the header. Is there a way to manually set boundaries for tooltips in ng-bootstrap? Unl ...

Ways to retrieve the ngValue from various select elements created in the HTML code

I'm dealing with a JSON list of roles that includes their id, name, and parent_id (referring to themselves). roles My goal is to display all the roles along with their names and corresponding parents. The parent will be displayed in a select input, ...

Using React.lazy, Suspense, and react-router-dom for code splitting in React does not function as intended

I'm currently working on setting up a simple example that is similar to the concept of lazy-loading route components as explained here: https://reactjs.org/docs/code-splitting.html#route-based-code-splitting The idea is to dynamically load ModuleOne ...

Different ways to categorize elements of Timeline using typescript

I have some code that generates a timeline view of different stages and their corresponding steps based on an array of stages. Each stage includes its name, step, and status. My goal is to organize these stages by name and then display the steps grouped un ...

Troubleshooting a useContext error in Next.js with TypeScript

I've been working on an app using next.js for the frontend, and I encountered an issue while trying to stringify an object. Here's a snippet of the error message: Argument of type '{ auth: dataObject; }' is not assignable to parameter o ...

Firebase authentication link for email sign-in in Angularfire is invalid

Currently, I am utilizing the signInWithEmailLink wrapper from AngularFire for Firebase authentication. Despite providing a valid email address and return URL as arguments, an error is being thrown stating "Invalid email link!" without even initiating any ...