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

Having trouble resolving parameters? Facing an Angular dependency injection problem while exporting shared services?

Seeking to streamline the process of importing services into Angular 4 components, I devised a solution like this: import * as UtilityService from '../../services/utility.service'; As opposed to individually importing each service like so: imp ...

Utilizing type arguments in JSX components when applying withStyles

When working with React and material-ui, I am attempting to create a JSX component that can accept generic parameters while also utilizing the withStyles Higher Order Component (HOC) to inject styles. The initial approach looked something like this: cons ...

Can @Input() be declared as private or readonly without any issues?

Imagine you're working in an Angular component and receiving a parameter from its parent. export class SomethingComponent implements OnChanges { @Input() delay: number; } Would it be considered good practice, acceptable, or beneficial to designat ...

How can I create an Array of objects that implement an interface? Here's an example: myData: Array<myInterface> = []; However, I encountered an issue where the error message "Property 'xxxxxx' does not exist on type 'myInterface[]'" appears

Currently, I am in the process of defining an interface for an array of objects. My goal is to set the initial value within the component as an empty array. Within a file, I have created the following interface: export interface myInterface{ "pictur ...

The serverTimeStamp() function in firebase.firestore.FieldValue does not allow for the Timestamp data type to be used

async addNewUser(id: string, email: string) { await this.afs.doc<MemberProfileModel>(FirestoreDbConstant.MEMBER_PROFILES + `/${id}`).set({ email, registeredDate: firebase.firestore.FieldValue.serverTimestamp(), }); } This appro ...

The code encountered an error with message TS2345 stating that the argument type '(a: Test, b: Test) => boolean | 1' cannot be assigned to a parameter type of '(a: Test, b: Test) => number'

Apologies for the lengthy subject, but I am having trouble understanding the response. Here is my code snippet: this.rezerwacjeFilteredByseaarchInput.sort(function (a, b) { if (a[5]===null) { // console.log(a[5]); return 1; } ...

Progress Bar Modules

I am currently working on creating a customizable animated progress bar that can be utilized as follows: <bar [type]="'health'" [percentage]="'80'"></bar> It is functional up to the point where I need to adjust different p ...

Hiding the line connector between data points in ChartJs

I recently took over a project that includes a line chart created using Chart.js by the previous developer. My client has requested that I do not display a line between the last two data points. Is this possible with Chart.js? I have looked through the doc ...

Exploring observables for querying the OMDB API and obtaining information on movies

Hey everyone, I'm currently working on implementing a live search feature using Observables in Angular2 to fetch Movie data from the OMDB API. While I can see that it is functioning correctly in the Chrome Network tab, the results aren't showing ...

UI and `setState` out of sync

Creating a website with forum-like features, where different forums are displayed using Next.js and include a pagination button for navigating to the next page. Current implementation involves querying data using getServerSideProps on initial page load, f ...

Guide on utilizing TypeScript declarations imported as `* as`

Currently, I am working with react-icons and attempting to import all icon definitions using the syntax import * as Icons from 'react-icons/fi'. However, I am facing a dilemma on how to create a type that must be one of the types exported from Ic ...

Angular asynchronous testing with Observable using karma

I am currently working on testing an asynchronous scenario. Here is a snippet of my component: ngOnInit(private service: MyService) { this.isLoading = true; this.service.getData().subscribe((data) => { this.data = data; this.isLoa ...

Can someone explain how to create a Function type in Typescript that enforces specific parameters?

Encountering an issue with combineReducers not being strict enough raises uncertainty about how to approach it: interface Action { type: any; } type Reducer<S> = (state: S, action: Action) => S; const reducer: Reducer<string> = (state: ...

Discover the steps to activate and utilize mat-error without the need for form control manipulation

Have you encountered an issue with using ngModel and mat-error without a form? Is there a workaround that allows the use of mat-error with ngModel? #code <mat-form-field appearance="fill" class="w-48per"> <mat-label>Fi ...

Issue encountered in Angular 2 while attempting to import TypeScript classes using a single file

Upon loading my Angular 2 application, I encountered the following error: EXCEPTION: Error: Uncaught (in promise): Unexpected piped value 'undefined' on the View of component 'DashboardComponent' An interesting observation is that by ...

What is the best way to perform a deep copy in Angular 4 without relying on JQuery functions?

Within my application, I am working with an array of heroes which are displayed in a list using *ngFor. When a user clicks on a hero in the list, the hero is copied to a new variable and that variable is then bound to an input field using two-way binding. ...

Addressing ESLint and TypeScript Issues in Vue.js with Pinia: A comprehensive guide

Experiencing difficulties with Vue.js + Pinia and need assistance to resolve these issues. Error: 'state:' is defined but never used. Here is the snippet of code located in @/stores/user.ts. import { defineStore } from 'pinia' export ...

In TypeScript Next.js 14 APP, object literals are limited to declaring existing properties

I encountered an error in my typescript next.js 14 APP. I need assistance resolving this issue, which states: Object literal may only specify known properties, and 'productPackages' does not exist in type '(Without<ProductCreateInput, Pr ...

Collaborate on sharing CSS and TypeScript code between multiple projects to

I am looking for a solution to efficiently share CSS and TS code across multiple Angular projects. Simply copy-pasting the code is not an ideal option. Is there a better way to achieve this? ...

A guide on parsing a stringified HTML and connecting it to the DOM along with its attributes using Angular

Looking for a solution: "<div style="text-align: center;"><b style="color: rgb(0, 0, 0); font-family: "Open Sans", Arial, sans-serif; text-align: justify;">Lorem ipsum dolor sit amet, consectetur adipiscing e ...