Determining interface value based on the presence of another optional interface value

I am working with an interface that looks like this:

export interface IButton {
 label: string;
 withIcon?: boolean;
 underlined?: boolean;
 selected?: boolean;
 iconName?: string;
 isLink?: boolean;
 href?: string;
 onCLick?: () => void;
}

My question is, can I conditionally use the iconName property based on whether withIcon is used?

For instance:

<Button label='test' /> ---> This should not throw an error.

<Button withIcon /> ---> This should throw an error alerting me that the iconName is missing.

Answer №1

To accomplish this, you can define a Union type called IconOptions that includes two possible structures:

type IconOptions = { withIcon?: false; iconName?: string; } | { withIcon: true; iconName: string; }

This definition indicates that when withIcon is set to true, iconName must be provided, otherwise it is optional.

Next step would involve adding this defined type as an intersection to the existing type IButton:

export type IButton = {
 label: string;
 underlined?: boolean;
 selected?: boolean;
 isLink?: boolean;
 href?: string;
 onCLick?: () => void;
} & IconOptions;

You can experiment with this concept in the TypeScript Playground through this link.

Answer №2

This situation appears to be akin to this question.

To resolve it, you can combine both potential scenarios into a union.

export type IButton = {
 label: string;
 underlined?: boolean;
 selected?: boolean;
 isLink?: boolean;
 href?: string;
 onCLick?: () => void;
} & ({
 iconName: string;
 withIcon: true
} | {
 iconName?: never;
 withIcon?: never | false
})

An error will occur if one property is used without the other.

function main(){
  return (
    <>
      <Button label="abc"></Button> // valid
      <Button label="abc" iconName="abc" withIcon></Button> // valid
      <Button label="abc" withIcon></Button> // error: Property 'iconName' is missing in type
      <Button label="abc" iconName="abc"></Button> // error: Property 'iconName' is missing in type
      <Button label="abc" withIcon={false} iconName="abc"></Button> // error: Types of property 'iconName' are incompatible
    </>
  )
}

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

What is the method for copying table data, including input text as cells, to the clipboard without using jQuery?

I have a basic table that looks like this: <table> <thead> <tr> <th>Savings</th> </tr> </thead> <tbody> <tr> <td>Savings <button type="button" (click)=" ...

The chosen index in the Material Stepper feature is experiencing a malfunction

I've been busy working on a Mat-Stepper, actually two of them. I have a component that contains two ng-templates set up like this: Question: Why is my selected index not functioning as expected? Am I missing something? I know you can define [selected ...

Combining union types with partial types in TypeScript: A guide

Consider the following type in TypeScript: type Input = { a: string b: number } | { c: string } How can we merge it into a partial type like this: type Result = { a?: string b?: number c?: string } We are seeking a type Blend<T>: type B ...

Hover Effect for 3D Images

I recently came across an interesting 3D Hover Image Effect that I wanted to implement - https://codepen.io/kw7oe/pen/mPeepv. After going through various tutorials and guides, I decided to try styling a component with Materials UI and apply CSS in a differ ...

Recursive rendering of tree components in React

I am facing a challenge in rendering tree items recursively using React. I have been struggling to achieve the desired outcome as calling treeRender(children) seems to alter the data structure when a folder is encountered for the first time. I am curious a ...

Revamp the button's visual presentation when it is in an active state

Currently, I'm facing a challenge with altering the visual appearance of a button. Specifically, I want to make it resemble an arrow protruding from it, indicating that it is the active button. The button in question is enclosed within a card componen ...

TypeORM find query is returning a data type that does not match the defined entity type

In my infrastructure module, I am using the code snippet below: import { Student } from "core" import { Repository } from "./Repository" import { Database } from "../../db" export class UserRepository<Student> extends Re ...

Transferring various sets of information into a single array

In an attempt to generate JSON data in an array for passing to another component, I followed a method outlined below. However, being relatively new to this field, my execution may not have been optimal as expected. employeeMoney: any[] = []; employeeId: an ...

What kind of function am I using and passing as props in React when working with TypeScript?

I recently developed a customized Checkbox component. The TypeScript setup in my project doesn't allow the use of any type, so I'm struggling to define the specific type for the handleCheckbox() function (found within the FilterBox component) th ...

How to use TypeScript to set a value in ng2-ckeditor

I have implemented two ckeditor instances using *ngFor: <div class="form-group" *ngFor="let lang of languages"> <span>Legal text in {{lang.translate}} {{lang.abbr}}</span> <ckeditor id="{{lang.abbr}}" formControlName="{{lang.abbr} ...

Enhancing a prototype instance in TypeScript while activating strict mode

When working with an instance named remote from a factory in a vendor script, I encountered the need to add my own methods and members to that instance. While seeking a solution, I came across an insightful response on extending this in a Typescript class ...

Using Angular 4 to transfer data from a dynamic modal to a component

Currently implementing material design, I have set up a dialogService for dynamically loading MdDialog. My goal is to create a search dialog with filters that, upon submission, directs the user to a search-results component route. However, I am struggling ...

Object.assign versus the assignment operator (i.e. =) when working with React components

Just a quick question: I've come across some answers like this one discussing the variances between Object.assign and the assignment operator (i.e. =) and grasp all the points made such as object copying versus address assignment. I'm trying to ...

Using Angular's ElementRef to set focus on an ion-textarea: "The 'setFocus' property is not found on the 'ElementRef' type."

After developing a textarea component that automatically focuses itself when created using the ngAfterViewInit() method, everything seemed to be working perfectly as expected. ngAfterViewInit() { if(this.text.length===0){ this.theinput.setFocus(); ...

Detecting changes in Angular when the @Input() value remains the same

I have created an Angular Custom scroll directive that utilizes an @Input() to pass an HTML element as a parameter, allowing the scrollbar to move to that specific element. However, I've encountered an issue where if I pass the same HTML Element mult ...

What is the importance of always catching errors in a Promise?

In my project, I have implemented the @typescript-eslint/no-floating-promises rule. This rule highlights code like this - functionReturningPromise() .then(retVal => doSomething(retVal)); The rule suggests adding a catch block for the Promise. While ...

NGXS Alert: Unable to resolve parameters for TranslationEditorState: (?)

I'm currently implementing NGXS for state management within my Angular 9 application. I've encountered a specific issue where any attempt at dependency injection in one of the state classes results in an error message stating "Error: Can't r ...

Which is more efficient: Storing the database as a private member variable in Ionic 3 SQLite or creating a new database for every query

Here's a question for you - in the context of Ionic 3, what would be the preferable approach: keeping the opened database as a private member variable within a database provider class, or calling create every time a query is made to the database? For ...

Is it impossible to extend a Typescript class with an overriding method that uses a different parameter?

I am currently working on a Typescript MVC app and encountering an issue. When I try to extend my BaseController and override the ajaxMethod with different parameters, my transpiler throws an error. Any help would be appreciated. Below is the code snippet ...

The variable 'minSum' is being referenced before having a value set to it

const arrSort: number[] = arr.sort(); let minSum: number = 0; arrSort.forEach((a, b) => { if(b > 0){ minSum += minSum + a; console.log(b) } }) console.log(minSum); Even though 'minSum' is defined at the top, TypeScript still throws ...