What is the best way to create an assertion function for validating a discriminated union type in my code?

I have a union type with discriminated properties:

type Status =
    { tag: "Active", /* other props */ }
  | { tag: "Inactive", /* other props */ }

Currently, I need to execute certain code only when in a specific state:

// At some point
const status: Status = …;

// Later on
if (status.tag !== "Active") {
  throw new AssertionError(…);
}

// Now I can be confident that `status` is of type "Active"

Is it possible to refactor the condition into an assert function?

// Somewhere
const assertStatus = (status: Status, tag: Status["tag"]) => ???

// And later:
assertStatus(status, "Active");

// Here I am sure `status` is of type "Active"

Answer №1

To achieve this, one can utilize assertion functions.

type State =
    { tag: "A", /* other properties */ }
  | { tag: "B", /* other properties */ }

function assertState (condition: boolean): asserts condition { 
  if (!condition) {
    throw new Error("message")
  }
}

function test(){
  let state: State = {} as any

  assertState(state.tag === 'A')

  state.tag // now only has type `A`
}

Playground

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

Create a reusable React component in Typescript that can handle and display different types of data within the same

I have a requirement to display four different charts with varying data types. For instance, interface dataA{ name: string, amount: number } interface dataB{ title: string, amount: number } interface dataC{ author: string, amount: ...

Error message in TypeScript: A dynamic property name must be a valid type such as 'string', 'number', 'symbol', or 'any'

Attempting to utilize the computer property name feature in my TypeScript code: import {camelCase} from "lodash"; const camelizeKeys = (obj:any):any => { if (Array.isArray(obj)) { return obj.map(v => camelizeKeys(v)); } else if (ob ...

Make sure to confirm that 'tables-basic' is an Angular component within the module before proceeding

In my table-basic.component.ts file, I declared 'tables-basic' as a selector and included this template in dashboard.html. Despite following the steps outlined below, I encountered an error which is also highlighted. Snippet from my dashboard.te ...

The function is trying to access a property that has not been defined, resulting in

Here is a sample code that illustrates the concept I'm working on. Click here to run this code. An error occurred: "Cannot read property 'myValue' of undefined" class Foo { myValue = 'test123'; boo: Boo; constructor(b ...

The paths configuration in tsconfig.json is not functioning as anticipated

I've been encountering a module not found error while trying to work with jasmine-ts. To troubleshoot, I decided to use tsc and inspect my folder structure: \src\app\... \src\tests\... To address this issue, I created a ...

What is the best way to implement an asynchronous function using a for loop and APIs in Typescript?

Struggling with ensuring my function returns data only after completing all API calls and the for loop. getListingsImages(sessionID, mlsSearchCriteria){ this.http.get(this.laconiaBaseURL + "mls/search/" + sessionID + "?" +querySt ...

Passing data from getServerSideProps to an external component in Next.js using typescript

In my Index.js page, I am using serverSideProps to fetch consumptions data from a mock JSON file and pass it to a component that utilizes DataGrid to display and allow users to modify the values. export const getServerSideProps: GetServerSideProps = async ...

Can the getState() method be utilized within a reducer function?

I have encountered an issue with my reducers. The login reducer is functioning properly, but when I added a logout reducer, it stopped working. export const rootReducer = combineReducers({ login: loginReducer, logout: logoutReducer }); export c ...

The function does not yield any result

import { Injectable } from '@angular/core'; export class Test { public id: number; public name: string; public fid: number }; export const TESTS2: Test[] = [ {id: 1, name: 'Lion', fid: 1}, {id: 2, name: 'Tiger', fid: 1 ...

Adding an item into a list with TypeScript is as simple as inserting it in the correct

I am working with a list and want to insert something between items. I found a way to do it using the reduce method in JavaScript: const arr = [1, 2, 3]; arr.reduce((all, cur) => [ ...(all instanceof Array ? all : [all]), 0, cur ]) During the fir ...

I'm having trouble with implementing a basic show/hide feature for the login and logout options in the navigation bar using Angular. Can anyone help me figure out why it's

Is there a way to display the functionality after logging in without using session storage or implementing the logout function? The HTML for navigation is provided below. <nav class="navbar navbar-expand-sm navbar-light bg-light"> ...

Customize your Joi message using the .or() method

I'm attempting to personalize a message for the .or() function in Joi, similar to this: https://i.stack.imgur.com/68dKx.png The default message from Joi is as follows: Validation Error: "value" must contain at least one of [optionOne, optionTwo] ...

Tips on identifying and handling errors without the need for type assertions in this code segment

My code is correct, but it's becoming difficult to maintain... interface FuncContainer<F extends (..._: Array<any>) => any> { func: F args: Parameters<F> } const func: FuncContainer<typeof Math.min> = { func: Math.min ...

Establishing a Next.js API endpoint at the root level

I have a webpage located at URL root, which has been developed using React. Now, I am looking to create an API endpoint on the root as well. `http://localhost:3000/` > directs to the React page `http://localhost:3000/foo` > leads to the Next API end ...

What is the best way to handle API requests within an Angular component?

I am currently diving into the world of Angular at my workplace, even though I do not have a background in web development. One challenge I am facing is how to encapsulate API calls within one of my components without knowing where to begin. The componen ...

Can you explain how to utilize multiple spread props within a React component?

I'm currently working in TypeScript and I have a situation where I need to pass two objects as props to my React component. Through my research, I found out that I can do this by writing: <MyComponent {...obj1} {...obj2} /> However, I'm fa ...

What advantages does CfnAppSync provide over using AppSync in a CDK project?

We are in the process of enhancing our API by adding new JS resolvers and phasing out the VTL resolvers for an AWS AppSync CDK project, specifically built with Cfn<> Cloud Front CDK. The code snippet below illustrates how this can be achieved: ...

unable to locate the custom npm package within my service

There is a similar inquiry posted here: My custom NPM Package is not found, but unfortunately, the solution provided did not fix my issue. I am encountering an error stating: "Could not find a declaration file for module '@dc_microurb/common' ...

Tips for scrolling ion-items vertically to the bottom and top using arrow icons in Ionic 4

I'm developing an Ionic 4 app with Angular and looking to incorporate Up and Down Arrow buttons for vertical scrolling from top to bottom and vice versa. ...

Navigating through the key type within a mapped structure

I am working with a mapped type in the following structure: type Mapped = { [Key in string]: Key }; My understanding is that this setup should only allow types where the key matches the value. However, I have found that both of the cases below are permitt ...