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 sets apart the commands npm install --force and npm install --legacy-peer-deps from each other?

I'm encountering an issue while trying to set up node_modules for a project using npm install. Unfortunately, the process is failing. Error Log: npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolv ...

The operation of the "CheckFileSystemCaseSensitive" task has encountered an unexpected failure. It was unable to load the file or assembly 'System.IO.FileSystem'

I recently upgraded my Visual Studio 2017 ASP.NET Core MVC web project by adding the Microsoft.TypeScript.MSBuild NuGet package v2.3.1 and updating my ASP.NET Core assemblies from 1.0.* to 1.1.1. However, after these changes, I encountered a new exception ...

The primary origin of TypeScript is derived from the compiled JavaScript and its corresponding source map

Being new to sourcemaps and typescript, I am faced with a project that has been compiled into a single javascript file from multiple typescript files. The files available to me are: lib.js (the compiled js code of the project) lib.js.map (the source map ...

What causes a standard React component with a default render prop to not pass PropTypes validation successfully?

I'm currently working on a React component with a render-prop that has a generic type. To improve usability, I want to set a default value for the render-prop. The code is functioning correctly, but during type-checking, I encountered a warning regard ...

Exploring the Impact of 2 HostBindings on Class Generation from Inputs in Angular 4

I'm struggling with the code in my component, which looks like this: @Component({ selector: "home", templateUrl: "./home.html" }) export class Home { constructor() {} @HostBinding("class") @Input() public type: string = "alert" @HostBindi ...

A Project built with React and TypeScript that includes code written in JavaScript file

Is it an issue when building a React project with Typescript that includes only a few JS components when moving to production? ...

Sharing a variable between an Angular component and a service

I am attempting to pass a variable from a method to a service. from calibration-detail.component.ts private heroID: number; getTheHeroID() { this.heroService.getHero(this.hero.id).subscribe(data =>(this.heroID = data.id)); } to step.service.ts I ...

What is the best way to ensure that Interface (or type) Properties always begin with a particular character?

I attempted to tackle this assignment using template literals, but unfortunately, I wasn't successful. Here is the interface that I am working with: interface SomeInterface { '@prop1': string; '@prop2': string; '@ ...

Regular expressions that identify text located at the conclusion of a URL

Although the title may not be entirely appropriate, my goal is to create a regex that will remove any trailing '/' at the end of a URL under certain conditions. For example: http://stackoverflow.com/questions/ask/ to http://stackoverflow.com/qu ...

The lazy loading feature in Angular 12 is not functioning correctly for path modules

My application has a jobs module with various components, and I'm trying to lazy load it. However, I've encountered an issue where accessing the module through the full path http://localhost:4200/job/artist doesn't work, but accessing it thr ...

Unlock the encrypted information in the blockchain

I've been working on encrypting and decrypting values using Node's built-in crypto module. I found a helpful tutorial that showed me how to encrypt the data, but it didn't provide any sample code for decryption. When I tried using code from ...

Is there Polyfill Compatibility for Custom Elements in Angular 9?

When it comes to polyfilling support for custom elements created with Angular, there are various recommendations available. This demo demonstrates that adding the following polyfill in polyfills.ts works: import '@webcomponents/webcomponentsjs/custo ...

Allow Visual Studio Code to create a constructor for Typescript class

When developing Angular 2 apps in Typescript using Visual Studio Code, one common task is writing constructors with their parameter list. Is there a way to save time and effort on this? It would be really helpful if the IDE could automatically generate th ...

How can jsPDF be used with Angular2 in Typescript?

Recently, I developed an Angular2 application that is capable of generating JSON data. My main goal was to store this JSON output into a file, specifically a PDF file. This project was built using Typescript. To achieve the functionality of writing JSON d ...

The attribute interface overload in Typescript is an important concept to

Consider a scenario where there are multiple payload options available: interface IOne { type: 'One', payload: { name: string, age: number } } interface ITwo { type: 'Two', payload: string } declare type TBoth = IOne ...

Retrieve user details from a NextJS application following a successful Keycloak authentication on a Kubernetes cluster

I've been attempting to retrieve the authenticated user information in my NextJS app after being redirected to it following a successful Keycloak login on a different tab located at localhost:8080/auth. The ingress (entry point) is responsible for ch ...

Can a single data type be utilized in a function that has multiple parameters?

Suppose I have the following functions: add(x : number, y : number) subtract(x : number, y : number) Is there a way to simplify it like this? type common = x : number, y : number add<common>() This would prevent me from having to repeatedly define ...

Check the type of the indexed value

I need help with a standard interface: interface IProps<T> { item: T; key: keyof T; } Is there a way to guarantee that item[key] is either a string or number so it can be used as an index for Record<string | number, string>? My codeba ...

Automatically divide the interface into essential components and additional features

Consider the following interfaces: interface ButtonProps { text: string; } interface DescriptiveButtonProps extends ButtonProps { visible: boolean, description: string; } Now, let's say we want to render a DescriptiveButton that utilize ...

Why won't Angular 4 create the node_modules folder when using ng new to initialize a new project?

Recently reinstalled Angular and began a new project using ng new. However, I encountered issues when trying to run ng serve after creating the project and changing into its directory. On my Mac Mini, I can simply navigate to the project folder and run ng ...