Determining the quantity of variations within a union in Typescript

Is it possible to determine the number of types in a union type in Typescript, prior to runtime? Consider the following scenario:

type unionOfThree = 'a' | 'b' | 'c';

const numberOfTypes = NumberOfTypes<unionOfThree>;
console.log(numberOfTypes); // 3

type unionOfFive = 1 | 2 | 7 | 15 | 23;

numberOfTypes = NumberOfTypes<unionOfFive>;
console.log(numberOfTypes); // 5

Although it seems like assigning a type as a value to a variable, conceptually this should be viable. Since the count of types in a union is static beforehand.

The motivation behind this is to check if a Set is at full capacity, allowing for validation like so:

const randomSet: Set<unionOfThree> = new Set();

...

if (randomSet.size === NumberOfTypes<unionOfThree>) {
  console.log('the set is full!');
}

While using if (randomSet.size === 3) is an option, relying on a hardcoded number may introduce errors when the union type evolves over time.

Answer №1

When dealing with union types in TypeScript, it can be challenging to create a numeric literal type that represents the number of members in a scalable way. Due to the lack of direct access to this information, manipulating unions becomes necessary. However, TypeScript does not support observing any particular order for unions (e.g., A | B being equivalent to B | A). This leaves developers with two less-than-ideal options: iterate over every ordering of the union (which scales poorly) or resort to unsupported tricks as discussed in "How to transform union type to tuple type". It is generally best to avoid these approaches, especially if there is control over the union's source.

An easier alternative involves starting with tuple types, which arrange the elements of the union in a specific order. For example:

type TupleOfThree = ["a", "b", "c"]; 
type TupleOfFive = [1, 2, 7, 15, 23];

Tuple types represent arrays with known lengths and orders. They are essentially specialized versions of standard array types like Array, containing familiar methods such as map(), filter(), and length. By creating an array of type TupleOfThree, indexing into it using a numerical key will yield a value corresponding to the union members. Similarly, accessing the length property of a value of type TupleOfThree will reveal the numeric literal type of its union size.

Assuming each element in the tuple corresponds to a single union member and no intentional deviations are made (e.g., mixing literals with unions), this method offers a straightforward solution:

const randomSet: Set<TupleOfThree[number]> = new Set();
const size: TupleOfThree["length"] = 3; // works fine
if (randomSet.size === size) {
    console.log('the set is full!');
}

Editing TupleOfThree to add more members would trigger a compile-time error:

type TupleOfThree = ["a", "b", "c", "d"]; // additional member "d"
const randomSet: Set<TupleOfThree[number]> = new Set();
const size: TupleOfThree["length"] = 3; // error!
//    ~~~~ <--- Type '3' is not assignable to type '4'.

To explore this concept further and experiment with the code, check out the playground link provided.

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 addition of types/cors in Express Typescript causes my POSTMAN request to hang indefinitely

I am experiencing an issue with my React web app and Express TypeScript backend. Previously, my POST request was functioning well, but now it seems to hang indefinitely on Postman without returning any errors. issueController.ts import { RequestHandler } ...

Angular 2's subscribe method allows for actions to be taken in response to

There are two buttons, one of which is hidden and of type file. When the user clicks the first button, a confirmation dialog opens. Upon clicking "Ok" in the dialog, the second button should be clicked. The issue arises when all the logic in the subscribe ...

Make sure to refresh the state of the store whenever there is a change detected in the input

I am experiencing an input delay problem when trying to update the state of a zustand variable in the onChange event. const BuildOrder = (props: { setOpen: Function }) => { const { almacenes, isLoadingAlmacenes } = useGetAlmacenes(); const { article ...

Angular's GET request response is returning an "Undefined" value instead of the

As an Angular beginner, I've successfully set up and tested a service that retrieves data from a JSON file using the Get method. However, when attempting to access the data inside the JSON file, it returns as undefined. My goal is to use this data as ...

When embedding HTML inside an Angular 2 component, it does not render properly

Currently, I am utilizing a service to dynamically alter the content within my header based on the specific page being visited. However, I have encountered an issue where any HTML code placed within my component does not render in the browser as expected ( ...

Checking if an instance belongs to a specific class using a custom type guard in TypeScript

After successfully implementing the function isInstanceOfClass, which determines if an instance is of a given class, I am now faced with the task of writing the correct typing for it. class Parent { isInstanceOfClass<T>(arg: T): this is T { ...

Creating a new component when a click event occurs in React

Currently diving into the world of React while working on a project that involves mapbox-gl. I'm facing an issue where I can successfully log the coordinates and description to the console upon hover, but I can't seem to get the popup to display ...

Testing Playwright - accessing variables from the .env file

I am currently working on a Playwright test script in TypeScript and I'm looking for a way to leverage variables from my .env file within the test. Does anyone know how this can be accomplished? ...

Having difficulty locating the correct TypeScript interface for executing GraphQL queries in a React application using Apollo Client

In this React component code snippet, a table is returned with each row containing data fetched from a backend API using GraphQL. While the data is successfully fetched, there seems to be an issue in defining the correct interface for handling the data ret ...

Is there a way to conceal an element within a component based on the current component being used with the router?

I have managed to hide an entire component, but I am unsure of how to show or hide specific elements within a component. export class AppComponent { headerFooterVisible: boolean; constructor(private router: Router) { router.events.subscribe(e =&g ...

How to Properly Initialize a Variable for Future Use in a Component?

After initializing my component, certain variables remain unassigned until a later point. I am seeking a way to utilize these variables beyond the initialization process, but I am unsure of how to do so. Below is my attempted code snippet, which throws a ...

What are the steps to resolve warnings in an imported json file?

I am working on a Vue project where I have imported a JSON file into my TypeScript script using import jsonData from '@/assets/data1.json'; Although the data is accessible and functions correctly, I am encountering numerous warnings during the b ...

Disabling ion-select in Ionic 2 with Typescript

To disable an ion-select element in Angular, you can use the disabled attribute like this: <ion-item> <ion-label stacked>Property Type</ion-label> <ion-select [(ngModel)]="propType" (ionChange)="ionChanger()" di ...

The error message "Property 'xy' is not found within the type '{}'. TS2339" indicates that the 'xy' property is not present

I've embarked on setting up a compact project utilizing react / typescript featuring the components below: App.tsx import React from "react"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Styles ...

An issue occurred with Ionic 4: TypeError - Unable to access property 'name' as it is undefined

None of the answers to similar questions have provided a solution for me SITUATION: I've been setting up a SQL Server connection from my Ionic app. You can check out my previous question for more details The workflow goes as follows: Ionic connects ...

Troubleshooting Angular 2: Why Array Interpolation is Failing

Greetings everyone, I am diving into Angular 2 and attempting to create a basic Todo application. Unfortunately, I've hit a roadblock. My array interpolation seems to be malfunctioning. Any assistance would be greatly appreciated. Here is my AppCompo ...

When using the `create-react-app` command with the `--typescript` flag, you may encounter an issue when attempting to compile namespaces with the `--

I started a project using npx create-react-app my-app-ts --typescript, then I added two new files, sw-build.js and sw.js in the src/ directory. The content of these files was taken from the discussion on Workbox guidelines at (Guidlines for Using Workbox) ...

Prevent selection of future dates in Kendo UI Calendar Widget

Can someone please advise on a method to disable future dates (i.e., gray them out) in the Kendo UI Calendar widget? I've attempted hiding the future dates, but it doesn't look good. I've also tried different ways to gray them out without su ...

Generate a commitment from the function

I know the basics of JavaScript Promise and promise chain, but I'm looking to deepen my understanding. For example, take a look at the method provided below. It's in TypeScript, but can be adjusted for JavaScript ES6. private InsertPersonInDB(p ...

Encountering a "Module parse failed" error with type annotations in Nextjs while using Yarn Workspaces

I decided to experiment with transitioning a project from using Vite and React to Next.js and React. After reviewing the documentation on this page: https://nextjs.org/learn-pages-router/foundations/from-react-to-nextjs/getting-started-with-nextjs I made t ...