What is the best way to verify that all elements within an object are 'false' except for one that is 'true'?

I am working with an object that has multiple boolean fields:

type SomeObject = {
  A: boolean
  B: boolean
  C: boolean
  ....
}

Is there a simple and efficient method to determine if all other fields (except for a specified one) are set to false?

We could take the brute-force approach and check each field individually:

let foo:SomeObject = {
  A: false
  B: false
  C: false
}
let isA = !(foo.B || foo.C)
let isB = !(foo.A || foo.C)
let isC = !(foo.A || foo.B)

However, I believe there might be a more elegant solution to this problem.

Answer №1

If you are looking for compile-time validation only, it can be achieved easily using a mapped type and an intersection (with an identity mapped type for aesthetics):

type SomeData = {
  A: boolean
  B: boolean
  C: boolean
}

type OneTrueOnly<T extends object, K extends keyof T> = {
    [P in K] : true
} & {
    [P in Exclude<keyof T, K>]: false
};

type Identity<T> = { [P in keyof T] : T[P] }

//{ A: true; } & { B: false; C: false; }
type test = OneTrueOnly<SomeData, "A">;

//{ A: true; B: false; C: false; }
type pretty = Identity<test>;

If you require compile-time type guarding to narrow down types later on, a union needs to be used. The previous type can serve as a foundation for another utility type:

type MaybeOneTrue<T extends object> = {
    [P in keyof T]: OneTrueOnly<T, P>
}[keyof T];

//OneTrueOnly<SomeData, "A"> | OneTrueOnly<SomeData, "B"> | OneTrueOnly<SomeData, "C">
type combo = MaybeOneTrue<SomeData>;

const process = (obj: combo) => {
    //narrowing the type to a union member:
    if(obj.A) {
        console.log(obj); //OneTrueOnly<SomeData, "A">
    }
};

If runtime checks are needed, there are options available. Below is both a type and runtime guard based on the previously defined mapped types (MaybeOneTrue and OneTrueOnly):

const checking = <K extends keyof combo>(obj: combo, key: K) : obj is Extract<combo, { [P in K] : true }> => {
    return Object.entries(obj).every(([k,v]) => k === key || !v );
};

{
    const obj:combo = { A:true, B:false,C:false };
    if(checking(obj, "A")) obj //OK, obj is OneTrueOnly<SomeData, "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

Angular checkboxes not updating with current values when submitted

I have defined a static array in TypeScript like this: permissions: any[] = [ { permission: "Read", enabled: true }, { permission: "Write", enabled: false }, { permission: "Delete", enabled: false }, { permission: "Edit", enabled: true } ...

Is it true that SPFx doesn't support JQuery?

Currently, I am in the process of developing a new SharePoint Web Part using SPFx generated by Yeoman. The scaffolding template is working well and I have encountered no issues adding NPMs for JQuery and JQueryUI. As I run GULP SERVE, everything seems to b ...

What is the best way to make one element's click event toggle the visibility of another element in Angular 4?

Recently diving into Angular, I'm working on a feature where users can toggle the visibility of a row of details by simply clicking on the item row. The scenario involves a table displaying log entries, each with a hidden row underneath containing spe ...

Can we verify if this API response is accurate?

I am currently delving into the world of API's and developing a basic response for users when they hit an endpoint on my express app. One question that has been lingering in my mind is what constitutes a proper API response – must it always be an o ...

Tips for integrating Excel files with NestJS

I'm in the process of developing a REST API that will utilize a third-party API to retrieve specific status information. The URLs needed for this API are stored in an Excel file, which is a requirement for this use case. My goal is to extract the URLs ...

Transforming a JavaScript component based on classes into a TypeScript component by employing dynamic prop destructuring

My current setup involves a class based component that looks like this class ArInput extends React.Component { render() { const { shadowless, success, error } = this.props; const inputStyles = [ styles.input, !shadowless && s ...

Encountering a Typescript error while attempting to utilize mongoose functions

An example of a User interface is shown below: import {Document} from "mongoose"; export interface IUser extends Document{ email: string; password: string; strategy: string; userId: string; isValidPassword(password: string): ...

Using Typescript: Defining a function parameter that can be either of two interfaces

While browsing through this specific question, I noticed that it was somewhat related to my current issue, although there were notable differences. In my scenario, I have a function named parseScanResults which accepts an object as its argument. This obje ...

Unlocking the union of elements within a diverse array of objects

I have an array of fields that contain various types of input to be displayed on the user interface. const fields = [ { id: 'textInput_1', fieldType: 'text', }, { id: 'selectInput_1', fieldType: 'sel ...

Creating the data type for the input file's state: React with Typescript

Encountering an error when attempting to define the type of a file object within state: Argument of type 'null' is not assignable to parameter of type 'File | (()=> File)'.ts. Currently working on an upload component that allows for ...

Tips for Resolving TypeScript Error 7053 when using the handleChange function in a React Form

Seeking assistance with creating a versatile handleChange function for a React form. The goal is for the handleChange function to update the state value whenever a form field is modified, while also accommodating nested values. Below is my attempt: const ...

Following the npm update, encountering errors with webpack

Upgrading the npm package to version 8.2.0 has caused issues in my React application. Here is a screenshot of the problem: https://i.stack.imgur.com/noQIz.png These are the error messages I see in the console: [HMR] Waiting for update signal from WDS.. ...

What is preventing the combination of brand enums in Typescript 3?

Utilizing brand enums for nominal typing in TypeScript 3 has been a challenge for me. The code snippet below demonstrates the issue: export enum WidgetIdBrand {} export type WidgetId = WidgetIdBrand & string; const id:WidgetId = '123' as Wi ...

Implementing canActivate guard across all routes: A step-by-step guide

I currently have an Angular2 active guard in place to handle redirection to the login page if the user is not logged in: import { Injectable } from "@angular/core"; import { CanActivate , ActivatedRouteSnapshot, RouterStateSnapshot, Router} from ...

Utilizing a TypeScript function to trigger an action from within a Chart.js option callback

Currently, I am utilizing a wrapper for Chart.js that enables an animation callback to signify when the chart has finished drawing. The chart options in my code are set up like this: public chartOptions: any = { animation: { duration: 2000, ...

Is there a way to sort through nested objects with unspecified keys?

I'm looking to extract specific information from a nested object with unknown keys and create a new array with it. This data is retrieved from the CUPS API, where printer names act as keys. I want to filter based on conditions like 'printer-stat ...

Angular 14 presents an issue where the injectable 'PlatformLocation' requires compilation with the JIT compiler; however, the '@angular/compiler' module is currently missing

I've encountered the following error and have tried multiple solutions, but none of them have been successful: Error: The injectable 'PlatformLocation' requires JIT compilation with '@angular/compiler', which is not available. ...

After adding the exclude property to angular-cli.json, the spec files are now being linted

I am working on an Angular 4 application and have manually created two .spec files for a specific class. When I use the nglint command, it successfully lints these two files. However, the spec files that were automatically generated when I created a compon ...

The requirement is for TypeScript to be cast as Partial<T>, with the condition that the keys

I'm currently looking for two different utility types: one that consists of a subset of a type with matching value types, and another that only requires the keys to exist in another type. I've devised the following solution, which appears to be ...

Tips for successfully passing function variables as parameters to Angular 2 HTTP subscribe callbacks

I attempted this.propositionService.addProposition(this.proposition) .subscribe(this.addSuccessCallback, this.addFailureCallback); The issue I am encountering is that both addSuccessCallback and addFailureCallback do not have acces ...