Select one of 2 parameters and begin typing

I recently encountered a situation where I needed to define a type with an id field (string) and an oldId field (number), but I wanted these fields to be exclusive.

For example:

{ id: "1234", name: "foo" }

{ oldId: 1234, name: "bar" }

I attempted the following code:

export type WithIdUnique<T> = T & ({ id: string } | { oldId: number })
export type ProductUnique = WithIdUnique<{
  name: string
}>

const product1Unique: ProductUnique = {
  oldId: 12345,
  name: "foo"
}

const product2Unique: ProductUnique = {
  id: "12345",
  name: "bar"
}

This implementation worked perfectly. However, when passing it as a parameter, I encountered an issue:

import { ProductUnique } from 'product'

export const someTestFunction = (productParam: ProductUnique) => {
  return product.id
}

The error message received was:

Property 'id' does not exist on type 'Product'.

Answer №1

To create the required type, you must combine a never with a union as shown in the example provided below.

The initial part of the type { name: string } serves as the "common" definition, which can consist of one or more properties.

This is then followed by a union of either "an id of type string but never an oldId" OR "an oldId of type number, but never an id". It's important to note that the nevers should have a ? in this scenario.

This pattern proves to be very useful in certain cases.

const product1 = { id: '1234', name: 'foo' };
const product2 = { oldId: 1234, name: 'bar' };
const product9 = { id: '1234', oldId: 1234, name: 'bar' };

type Product = { name: string } & (
  | {
      id: string;
      oldId?: never;
    }
  | {
      id?: never;
      oldId: number;
    }
);

const printProduct = (product: Product) => {
    console.log(product.name);
}

printProduct(product1);
printProduct(product2);
printProduct(product9); // <-- will not be accepted since product9 includes both an id and an oldId

Check Playground here

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 determine the present date within a template?

In my component, I am working with an object that contains a timestamp. What I aim to achieve is to dynamically check this timestamp in the template at runtime. For instance, I want to display the online status of a member by showing a green dot if they a ...

Creating a definition for the use of sweet alerts within a service and incorporating them through

Implementing sweet alert for displaying alert messages in angularJS2/typescript. Due to the repetitive nature of this code in different parts of the application, a service was created. @Injectable() export class AlertMessageService { constructor(pr ...

Having trouble with @viewChild not activating the modal popup and displaying an error message stating that triggerModal is not a function in

I am facing an issue where the click event is not being triggered from the parent component to display a Bootstrap 3 modal. I am getting the following error: ERROR TypeError: this.target.triggerModal is not a function This is what I have done so far: Pa ...

The Vite proxy server will not modify POST requests

When I set up a proxy using Vite, I noticed that it only handles GET and HEAD requests. I'm looking to have other request methods proxied as well. In a new Vite React project - the only modification I made was in vite.config.ts import { defineConfig ...

A method for performing precise division on numbers in JavaScript, allowing for a specific precision level (such as 28 decimal places)

I've searched extensively for a library that can handle division operations with more than 19 decimal places, but to no avail. Despite trying popular libraries like exact-math, decimal.js, and bignumber.js, I have not found a solution. How would you ...

Issue with SignalR client functionality following update to .NET Core 3.1版本

Upon updating our server-side code to asp.net core 3.1, we encountered an issue with the javascript client for signalr (@microsoft/signalr 3.1.0). The errors we are facing are: https://i.sstatic.net/ITZyK.png Here is the code snippet for the hub initial ...

Achieve flattening of types using recursion in TypeScript with the help of const

I am presenting the TypeScript code below: type Item = { key: number; value: string; items?: readonly Item[]; } const items = [ { key: 1, value: 'foo', items: [{ key: 3, value: 'baz' }] }, { key: 2, value: 'bar ...

Optimizing your data layer in Angular2: A Guide to Best Practices

As a newcomer to Angular2, I am diving into hands-on learning. My current project involves building multiple views with parent components, child components, and database services. After successfully creating one view, I am now gearing up to implement other ...

Eliminating an element from an object containing nested arrays

Greetings, I am currently working with an object structured like the following: var obj= { _id: string; name: string; loc: [{ locname: string; locId: string; locadd: [{ st: string; zip: str ...

combineLatest will trigger only for the initial event

I am looking to combine 3 events and trigger a service call when any of them are fired. Currently, I am using the combineLatest method, but it seems to only work when the first event is triggered by filterChanged. The issue here is that filterChanged is a ...

Removing redundant names from an array using Typescript

My task involves retrieving a list of names from an API, but there are many duplicates that need to be filtered out. However, when I attempt to execute the removeDuplicateNames function, it simply returns an empty array. const axios = require('axios&a ...

Explore one of the elements within a tuple

Can we simplify mapping a tuple element in TypeScript? I'm seeking an elegant way to abstract the following task const arr: [string, string][] = [['a', 'b'], ['c', 'd'], ['e', 'f']] const f ...

Ways to assign values to an array within an object

I'm attempting to transfer the contents of one array into an array within an object, but I keep encountering this error: Type 'any[]' is not assignable to type '[]'. Target allows only 0 element(s) but source may have more. Here ...

Angular error: Trying to assign a value of type ArrayBuffer to a string type

Is there a way to display a preview of a selected image before uploading it to the server? Here is an example in HTML: <div id="drop_zone" (drop)="dropHandler($event)" (dragover)="onDragover($event)"> <p>drag one or more files to ...

TypeScript's conditional property failing to recognize incorrect functional argument

The concept of a conditional type should encompass smart properties, and I sought assistance from @jcalz in the previous iteration of this query. Even though that issue was resolved, I am still unable to achieve the level of typing strictness I desire. The ...

Optimizing File Transfers and Streaming Using Next.js and CDN Integration

As I work on developing a download system for large files on my website using Next.js and hosting the files on a CDN, I face the challenge of downloading multiple files from the CDN, creating a zip archive, and sending it to the client. Currently, I have i ...

Tips for accessing the 'index' variable in *ngFor directive and making modifications (restriction on deleting only one item at a time from a list)

Here is the code snippet I'm working with: HTML: <ion-item-sliding *ngFor="let object of objectList; let idx = index"> <ion-item> <ion-input type="text" text-left [(ngModel)]="objectList[idx].name" placeholder="Nam ...

Testing the GET method in an Angular service: A guide

I'm currently facing an issue with my service method and unit test setup. Despite writing a unit test for the getter method, the coverage report indicates that this method is not covered. I would appreciate any advice on what might be going wrong in m ...

In TypeScript, use a Record<string, any> to convert to {name: string}

I have developed a custom react hook to handle API calls: const useFetch: (string) => Record<string, any> | null = (path: string) => { const [data, setData] = useState<Record<string, any> | null>(null); var requestOptions: Requ ...

How to display specific JSON objects that meet particular criteria in HTML cards using Ionic and Angular?

As a beginner in Ionic/Angular, I am attempting to fetch data from a JSON file and display it using cards in the HTML. The JSON contains numerous objects that are either marked as "deTurno == true" or "deTurno == false". Here is what I have so far: publi ...