How can we ensure that only one of two props is specified during compilation?

I've designed a customized Button component.

interface Button {
    href?: string;
    action(): void;
}

I'm looking to ensure that when a consumer uses this Button, they can only pass either href or action as a prop, not both.

I want TypeScript to validate this requirement during compilation. Can you suggest how I could achieve this?

Answer №1

If you want to specify a type that can have one property or another, you can use a union type

type Car = {
    color: string;
    speed?: never
} | {
    speed: number;
    color?: never;
}

let car1: Car = { color: "red" };
let car2: Car = { speed: 100 };
let car3: Car = { speed: 50, color: "blue" }; // error

To trigger an error, make sure to include optional never properties in the union type definition. This is necessary because of how excess property checks function. You can learn more about this concept here. Alternatively, you could explore using the StrictUnion type mentioned in the linked resource, though it may be excessive for handling just two properties.

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

How can Mui typescript be extended with a unique wrapper that includes a `component` property?

I recently created a unique wrapper component: import Box, { BoxProps } from "@mui/material/Box"; type CustomWrapperProps = { id: string } & BoxProps const CustomWrapper = (props: CustomWrapperProps) => { const {id, children, ...rest ...

Tips for updating parameters that are defined in a controller within a promise

Currently, I am developing a single page application using Angular and TypeScript. I am facing an issue with updating the parameter value (_isShowFirst) of the controller inside a promise function. It seems like nothing is recognized within the promise blo ...

Creating a function that operates according to the input parameter

Imagine a scenario where I am working with the following JS function: function fetchValue(keyName) { return x => x[keyName]; } Is it possible to define fetchValue in such a way that Typescript's type inference automatically determines the outp ...

Constructing a hierarchical tree structure using an array of objects that are initially flat

My goal is to create a hierarchical tree structure from a flat array: The original flat array looks like this: nodes = [ {id: 1, pid: 0, name: "kpittu"}, {id: 2, pid: 0, name: "news"}, {id: 3, pid: 0, name: "menu"}, {id: 4, pid: 3, name: ...

Which event is triggered following the update of all values in reactive forms?

How can I properly emit an event in Angular (v.5 or v.6) after a specific input of a reactive form has been changed? Here are the approaches I have tried: (ngModelChange)="doSomething($event)" (HTML, basic event) (bsValueChange)="doSomething($event) ...

Strategies for Implementing Pagination in an Angular 2 HTML Table Without the Use of Third-Party Tools

I have an HTML table that displays basic details along with images. I am looking to implement pagination for this table in Angular 2. Are there any alternatives to using ng2-pagination? ...

TypeScript: Defining a custom object type using an array of objects

Is there a way to dynamically generate an object based on the name values in an array of objects? interface TypeA { name: string; value: number; } interface TypeB { [key: string]: { value: any }; } // How can we create an OutputType without hard ...

Is it possible to link fields with varying titles in NestJS?

Currently, I am developing a NestJS application that interacts with SAP (among other external applications). Unfortunately, SAP has very specific field name requirements. In some instances, I need to send over 70 fields with names that adhere to SAP's ...

Is there an alternative method to incorporate the 'environment.ts' file into a JSON file?

In my Angular application, I need to import assets based on the env configuration. I am attempting to extract the patch information from environment.ts and save it into my assets as a json file. However, I am unsure of the proper method to accomplish this. ...

Error message: The provider is not being recognized by react-redux while using NextJS with RTK and

Struggling to integrate Redux RTK into my Next JS 13.4 app has been quite the challenge. No matter how many tutorials I follow, I keep encountering the same error in my provider.ts file. 'use client' import { store } from './store'; imp ...

Remove an item from the DOM instantly with React

Having trouble synchronously removing a child from the container? Here is a simplified code snippet demonstrating the current solution using the useState hook. type ChildProps = { index: number; id: string; remove: (index: number) => void; }; fun ...

Using jQuery with Angular 4 allows for powerful front-end development

To include jQuery in an Angular4 project, I follow these steps: npm install --save jquery npm install --save-dev @types/jquery In the app.component.ts file import $ from 'jquery'; or import * as $ from 'jquery'; When running "ng se ...

Using query parameters in Angular to interact with APIs

One scenario involves a child component passing form field data to a parent component after a button press. The challenge arises when needing to pass these fields as query parameters to an API endpoint API GET /valuation/, where approximately 20 optional p ...

The type 'ClassA<{ id: number; name: string; }>' cannot be assigned to the type 'ClassA<Record<string, any>>'

One requirement I have is to limit the value type of ClassA to objects only. It should also allow users to pass their own object type as a generic type. This can be achieved using Record<string, any> or { [key: string]: any }. Everything seems to be ...

Tests in headless mode with Cypress may fail sporadically, but consistently pass when running in a real browser

Currently, I am utilizing Cypress 9.5 to conduct tests on an Angular 13 application with a local PHP server as the backend. Throughout the testing process, I have encountered successful results when running the tests in the browser multiple times. However ...

What steps can be taken to resolve the Typescript errors related to the window object in my Vue application?

Within my Vue 3 app component, I need to interact with custom properties on the Window object, as shown below: window.ZohoHCAsapSettings = { //<-- ERROR HERE ticketsSettings: { preFillFields: { email: { defaultValue: user.value?.emai ...

Issue with font-size changes using css variables in Angular not updating in browser for specific fields

Utilizing CSS variables, I have implemented a feature that allows users to adjust the font size to small, medium, or large. While this functionality works correctly for most fields, there are certain instances where the value is applied but not displayed. ...

Encountering a 403 error when attempting to upload files to Google Cloud Storage (GCS) using Signed URLs

The main aim is to create a signed URL in the api/fileupload.js file for uploading the file to GCS. Then, retrieve the signed URL from the Nextjs server through the nextjs API at localhost://3000/api/fileupload. Finally, use the generated signed URL to upl ...

Injection of environmental variables into app services

Through the use of Nx, I have created multiple apps that each have their own environment with different API URLs. The Nx Workspace library includes shared services that are utilized among all apps, however, it is necessary to pass the environment-api-url w ...

The Intersection Observer API is caught in a never-ending cycle of rendering

I am experimenting with the intersection observer API in order to selectively display elements in a CSS grid as the user scrolls, but I seem to have run into a problem of encountering an endless rendering loop. Below is the code snippet I am working with. ...