Ensuring either of two properties is required in a Typescript Class

DISCLAIMER: While this question may seem similar to a thread on Stack Overflow, the solutions provided there do not apply to Classes. Due to the limitations in extending interfaces with classes, I'm facing a challenge.

I have encountered an intriguing problem that I would like to tackle for my own educational purposes. My goal is to define a class where either bankAccountNumber or encryptedBankAccountNumber must be present for a transaction.

export class AchDetails {
    'bankAccountNumber'?: string;

    'encryptedBankAccountNumber'?: string;
   
    'type'?: AchDetails.TypeEnum;

    static discriminator: string | undefined = undefined;

    static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
        {
            "name": "bankAccountNumber",
            "baseName": "bankAccountNumber",
            "type": "string"
        },
        {
            "name": "encryptedBankAccountNumber",
            "baseName": "encryptedBankAccountNumber",
            "type": "string"
        }   
        ];

    static getAttributeTypeMap() {
        return AchDetails.attributeTypeMap;
    }
}

export namespace AchDetails {
    export enum TypeEnum {
        Ach = 'ach',
        AchPlaid = 'ach_plaid'
    }
}

I wanted to implement the solution suggested in the previously linked issue, but it doesn't seem feasible as external typings cannot be used directly with Classes:

interface AchBaseDetails {
    'bankAccountNumber'?: string;
    'encryptedBankAccountNumber'?:string;
}


type RequireBankNumberType<T, Keys extends keyof T = keyof T> =
    Pick<T, Exclude<keyof T, Keys>>
    & {
        [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>
    }[Keys]

export type RequiredAchDetails = RequireBankNumberType<AchBaseDetails, 'bankAccountNumber' | 'encryptedBankAccountNumber'>

Is there a way to achieve this requirement while still working within the constraints of a Class?

Answer №1

To initiate the constructor, you can pass an argument that adheres to the mentioned pattern in the linked inquiry.

type Enc = {encrypted: string}
type Unenc = {notEncrypted: string}
type AccNum = Enc | Unenc;

function isEnc(acct: AccNum): acct is Enc {
  return typeof (acct as Enc).encrypted === 'string';
}

class Acc {
  public constructor(private account: AccNum) {}

  getBal(): number {
     if (isEnc(this.account)) {
         return fetchBalanceFromUnencrypted(this.account.encrypted);
     } else {
         return fetchBalanceFromEncrypted(this.account.notEncrypted);
     }
  }
}

const account1 = new Acc({encrypted: 'test'});
const account2 = new Acc({notEncrypted: 'example'});
// Will not compile
const invalidAccount = new Acc({x: 12, encrypted: 'data'});
// Will not compile
const invalidAccount2 = new Acc({});

Check out this TS playground example

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 best way to import a data type from another file into a `.d.ts` file without converting it into a module?

Recently encountered a peculiar scenario involving d.ts files and namespaces. I have some d.ts files where I define and merge a namespace called PROJECT. Take a look at how it's declared and automatically merged (across multiple files) below: file1 ...

Utilize Firebase Realtime Database to generate new data entries using triggers

Hey there, to all the amazing folks at stackoverflow who have been supporting me over the years, I have a new question for you! I've been delving into Android programming for quite some time now and I enjoy exploring different ways to optimize apps. ...

Converting language into class components using ngx-translate in Angular

Seeking to convert the information from a table into my typescript class. The data in the table is sourced from a JSON file within the /assets directory. Is there a method to accomplish this task? How can I categorize translation within a typescript class ...

Utilizing precise data types for return values in React hooks with Typescript based on argument types

I developed a react hook that resembles the following structure: export const useForm = <T>(values: T) => { const [formData, setFormData] = useState<FormFieldData<T>>({}); useEffect(() => { const fields = {}; for (const ...

Tips for restricting search results in Angular12

I've been attempting to restrict the number of results displayed in the table using ngrepeat with limitTo, but unfortunately, it's not functioning as expected. Below is a snippet of my code: busqueda.component.ts import { Component, OnInit } fr ...

Guide for integrating CryptoJS with Angular 2 and TypeScript within a WebPack build setup

Looking for advice on integrating the CryptoJS library with Angular 2 using TypeScript? Many existing resources are outdated and assume the use of SystemJS. Can someone provide straightforward instructions for incorporating CryptoJS with Angular 2 and Type ...

Familial Connection (TYPESCRIPT)

Is there a way to set the state in ISetOpen based on the type of modal in ISetOpen? For example: If ISetOpen.modal is 'payModal': Set ISetOpen.state to IPayModal If ISetOpen.modal is 'deleteModal': Set ISetOpen.state to IDeleteModal ...

How can I showcase the captured image on Ionic 2?

I am having trouble displaying the selected or captured image on the page after uploading it through two methods - one using the gallery and the other using the camera. ** Here is my code ** 1) profile.html: <img class="profile-picture" src="{{baseUr ...

Cannot utilize the subscribed output value within the filter function

I am in need of assistance with my Angular 7 project. I have successfully implemented a service to call a Json file and output an object array. However, I am facing an issue when trying to filter the objects in the array based on a specific property called ...

Tips for type guarding in TypeScript when using instanceof, which only works with classes

Looking for a way to type guard with TypeScript types without using instanceof: type Letter = 'A' | 'B'; const isLetter = (c: any): c is Letter => c instanceof Letter; // Error: 'Letter' only refers to a type, but is being ...

Angular 5 HttpClient fails to send a request

I'm encountering an issue with HttpClient while using Angular 5. The problem is that HttpClient doesn't seem to send any request (no xhr log appears in the console) on two specific components. However, it works perfectly fine on other components. ...

Encountering TS7016 error in simple webpack TypeScript demo due to node_module inclusion issue

Attempting to follow the official webpack typescript integration guide at https://webpack.js.org/guides/typescript/ but encountering errors. What could be the missing piece? ERROR in /Users/kevzettler/code/hypeworks/src/index.ts ./src/index.ts [tsl] ERROR ...

Is there a way to incorporate the value of a TypeScript enum into my JavaScript function?

After creating the appRun.ts file, I included references to app.ts and EnumsService.ts: /// <reference path="app.ts"/> /// <reference path="services/EnumsService.ts"/> app.run(['$rootScope', appRun]); function appRun($rootScope) { ...

Simulating a continuous key press on the keyboard for 5 seconds with TestCafe

Despite my attempts to send it to the browser console by using .pressKey("PageDown") after tracking it, nothing seems to be happening. I'm at a loss on what steps to take next - perhaps there are some examples available? I was advised to uti ...

Avoid allowing generic types to be overwritten in Typescript

Is there a way to ensure that the layoutKey remains as type L (specifically IOfficialLevelLayouts) even when passing in other values? Every time I provide a value, it seems to override the desired type. https://i.sstatic.net/YfH6k.png https://i.sstatic.ne ...

What are the steps to incorporating a personalized component into an extension?

I am working on a TypeScript file that includes a class inheriting cc.Component. My goal is to package this file as an extension and make it easily accessible within the editor, allowing users to add it to a node with ease. What steps should I take to ac ...

Why is it necessary to merge an interface with a function when using the new keyword?

Assuming that the setting noImplicityAny is enabled. Consider the following: function Bar() { this.f = 100; } The following code snippet will not function as expected: let x = new Bar(); An error message will be displayed: 'new' expre ...

What is the proper way to import and define typings for node libraries in TypeScript?

I am currently developing a node package in TypeScript that utilizes standard node libraries such as fs, path, stream, and http. Whenever I attempt to import these libraries in a .ts file, VS Code flags the line with an error message: [ts] Cannot find m ...

The Discordjs v13.1 bot is having trouble generating audio from an mp3 file

Having an issue with my bot playing an mp3 file. It successfully joins the voice chat and starts playing, but there is no audio output. The bot icon lights up green indicating it's playing, but no sound is heard. Here's the code snippet: awa ...

Can anyone help me understand the meaning of this unfamiliar icon in WebStorm's autocomplete feature

When the autocompletion feature is performing type inference, you will see this icon: https://i.sstatic.net/zOZcC.png ...