Creating an object type that includes boolean values, ensuring that at least one of them is true

To ensure both AgeDivisions and EventStyles have at least one true value, I need to create a unique type for each.

These are the types:

type AgeDivisions = {
  youth: boolean;
  middleSchool: boolean;
  highSchool: boolean;
  college: boolean;
  open: boolean;
};

type EventStyles = {
  folkstyle: boolean;
  freestyle: boolean;
  grecoRoman: boolean;
  jello: boolean;
  noGiJits: boolean;
  giJits: boolean;
  judo: boolean;
  beach: boolean;
};

type EventInfo = {
  name: string;
  venueName: string;
  address: string;
  date: string;
  subTitle: string;
  country: string;
  eventType: EventType;
  hasGirlsOnlyDivision: boolean;
  link: string;
  ageDivisions: AgeDivisions;
  eventStyles: EventStyles;
  latitude: string;
  longitude: string;
  description: string;
};

I believe creating unique types for AgeDivisions and EventStyles is the best way to achieve this requirement, rather than using a generic type.

Answer №1

Create your custom utility type called AtLeastOneTrue<K> which accepts a union of key types K and generates a new union where each member contains all boolean properties except for one that must be true. This allows multiple values to be true while ensuring that they cannot all be false. Here is an example implementation:

type AtLeastOneTrue<K extends string> = 
  { [P in K]: { [Q in K]: Q extends P ? true : boolean } }[K]

This structure acts like a distributive object type (as introduced in ms/TS#47109). If you have a union of key-like types K which resolves to K1 | K2 | K3, and want to convert it to

F<K1> | F<K2> | F<K3>
, you can use a distributive object type of the form {[P in K]: F<P>}[K]. This technique creates a new object type and immediately retrieves a union of its properties, even if F<P> yields objects.

The inner operation F<P> represents

{[Q in K]: Q extends P ? true : boolean}
. The conditional type Q extends P ? true : boolean serves to generate boolean properties for every key, except for the focused one which will always be true.


Let's illustrate this with the AgeDivisions example:

type AgeDivisions = AtLeastOneTrue<
  "youth" | "middleSchool" | "highSchool" | "college" | "open"
>;

/* Output:
{
    youth: true;
    middleSchool: boolean;
    highSchool: boolean;
    college: boolean;
    open: boolean;
} | {
    youth: boolean;
    middleSchool: true;
    highSchool: boolean;
    college: boolean;
    open: boolean;
} | { ⋯        
    highSchool: true;        
⋯ } | { ⋯
    college: true;       
⋯ } | {
    youth: boolean;
    middleSchool: boolean;
    highSchool: boolean;
    college: boolean;
    open: true;
}
*/

Ensure that the behavior aligns with expectations:

let a: AgeDivisions;
a = { college: false, highSchool: false, middleSchool: true, 
  open: false, youth: false }; // valid
a = { college: true, highSchool: false, middleSchool: false, 
  open: true, youth: false }; // valid
a = { college: false, highSchool: false, middleSchool: false, 
  open: false, youth: false }; // error

Looks promising! You can then define another type like EventStyles:

type EventStyles = AtLeastOneTrue<
  "folkstyle" | "freestyle" | "grecoRoman" | "jello" | 
  "noGiJits" | "giJits" | "judo" | "beach"
>;

Playground link to code

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

Is there a way to customize the slicing of *ngFor in a component according to the components it is being injected into?

This code snippet represents a component that needs to be included in other components: <div class="row"> <div class="col-12 [...]" *ngFor="let course of courses"> <div class="card"> ...

Bidirectional binding with complex objects

In my Angular2 app, I have a class called MyClass with the following structure: export class MyClass { name: Object; } The name object is used to load the current language dynamically. Currently, for two-way binding, I am initializing it like this: it ...

Understanding Different Symbols in TypeScript

Can you explain the purpose of symbols in TypeScript to me? As someone familiar with Java, it seems a bit unnecessary to use them alongside an interface declaration. What is the reason for setting symbols in TypeScript? For example, consider the followin ...

The Tauri JS API dialog and notification components are failing to function, resulting in a null return value

Currently, I am getting acquainted with the tauri framework by working on a small desktop application. While testing various tauri JS API modules, most of them have been functioning as expected except for the dialog and notification modules. Whenever I tes ...

Angular - Highlight a section of a string variable

Is there a way to apply bold formatting to part of a string assigned to a variable? I attempted the following: boldTxt = 'bold' message = 'this text should be ' + this.boldTxt.toUpperCase().bold() ; However, the HTML output is: thi ...

Exploring the Observable object within Angular

As I delve into learning Angular through various tutorials, I encountered a perplexing issue regarding my console displaying an error message: ERROR in src/app/employee/employee.component.ts:17:24 - error TS2322: Type 'IEmployee' is not assignab ...

Setting a default value for NULL property in TypeScript

Trying to establish a default value for all NULL objects has been quite the challenge. The current code looks like this: private setDisplayAmount(summaries: summary[]): void { summaries.map(t => { // performing some operations, and then... ...

Looking for a solution to the error message: "X is not able to be assigned to the type 'IntrinsicAttributes & Props'"

Greetings everyone! I need some assistance in setting up single sign-on authentication using React, Azure AD, and TypeScript. I'm encountering a type error in my render file and I'm unsure of how to resolve it. Below is the specific error message ...

Conditionally typing in TypeScript to check if a string contains a specific value

Looking to create a function that takes a string as input and determines whether it contains '[]' or not. If it does, the function should return a list, otherwise an object. This is what I have so far: function customFunction<T = any>(input ...

Obtain a union type in TypeScript based on the values of a field within another union type

Is it feasible in Typescript to derive a union type from the values of a field within another union type? type MyUnionType = | { foo: 'a', bar: 1 } | { foo: 'b', bar: 2 } | { foo: 'c', bar: 3 } // Is there an automati ...

Angular 5 Dilemma: Exporting UI Components without Locating Template

My current project involves developing UI Components that will be used in various web projects within the company. Our plan is to publish these UI components as an npm package on our local repository, and so far, the publishing process has been successful. ...

Ways to define an interface that can accommodate various interfaces with a specific structure

I am in need of a function that can accept a parameter with interfaces having a specific structure. The parameter should be either a string hash or a string hash along with an attribute string hash, as shown below: { anotherHash: { a: 'a', ...

What is preventing me from utilizing the import syntax to bring in a coffeescript file within typescript?

So here's the deal: I've got a typescript file where I'm importing various other typescript files like this: import ThingAMajig from '../../../libs/stuffs/ThingAMajig'; // a typescript file However, when it comes to importing my ...

Steps for preventing text manipulation in ng2-ace-editorWould you like to restrict users from copying, pasting

How can I prevent users from copying, pasting, and dropping text in ng2-ace-editor? https://github.com/fxmontigny/ng2-ace-editor is the library I implemented in my Angular 5 application. ...

It appears that Yarn is having trouble properly retrieving all the necessary files for a package

Recently, I encountered a strange issue in our project involving 3 microservices, all using the exceljs library. Two of the microservices successfully download all necessary files for this package through yarn. However, the third microservice is missing ...

Utilizing TypeScript's higher-order components to exclude a React property when implementing them

Trying to create a higher-order component in TypeScript that takes a React component class, wraps it, and returns a type with one of the declared properties omitted. Here's an attempt: interface MyProps { hello: string; world: number; } interfac ...

user interface grid element in Materia

After writing this code, I encountered the following error: No overload matches this call. Overload 1 of 2, '(props: { component: ElementType<any>; } & SystemProps<Theme> & { children?: ReactNode; classes?: Partial<GridClasses>; .. ...

When converting a PDF to a PNG, the precious data often disappears in the process

I am currently facing a problem with the conversion of PDF to PNG images for my application. I am utilizing the pdfjs-dist library and NodeCanvasFactory functionality, but encountering data loss post-conversion. class NodeCanvasFactory { create(w, h) { ...

Creating a type in TypeScript with keys as values taken from another type

There is an object const navigatorNames: NavigatorNamesType = { homeNavigation: 'HomeNavigation', authNavigation: 'AuthNavigation' } with the type defined as type NavigatorNamesType = { homeNavigation: 'HomeNavigation ...

Creating the upcoming application without @react-google-maps/api is simply not possible

After incorporating a map from the documentation into my component, everything seemed to be functioning correctly in the development version. However, when attempting to build the project, an error arose: Type error: 'GoogleMap' cannot be used as ...