How can I create a Typescript declaration where one value is dependent on the type of another?

Here is some code that I am working on:

type ValidationResult = 'OK' | 'MISSING_FIELDS' | 'DUPLICATED_FIELD';

type ValidationResultOkDetails = null;
type ValidationResultMissingFieldsDetails = [string];
type ValidationResultDuplicatedField = string;

type Validation = {
  result: ValidationResult,
  details: any
}

I am exploring whether there is a way in Typescript to specify that when the field result of the Validation type is set to 'OK', then the details should be interpreted as ValidationResultOkDetails. Similarly, if the result is 'MISSING_FIELDS', then the details should match

ValidationResultMissingFieldsDetails
, and so forth.

Answer №1

interface Validation {
  result: 'OK';
  details: ValidationResultOkDetails;
} | {
  result: 'MISSING_FIELDS';
  details: ValidationResultMissingFieldsDetails;
};

While it may seem a bit tangled, this is the most elegant solution I am aware of for addressing the issue at hand. There might be alternative approaches known to other individuals.

Answer №2

When it comes to OK having no data, the approach I would take is as follows (including an example for usage/checking). The compiler is able to determine the type based on the value in result.

I have defined the individual types separately, but they could also be declared inline within the Validation declaration if preferred (keep them separate if you need explicit references).

type ValidationResult = 'OK' | 'MISSING_FIELDS' | 'DUPLICATED_FIELD';

type ValidationResultOkDetails = null;
type ValidationResultMissingFieldsDetails = [string];
type ValidationResultDuplicatedField = string;

type ValidationOK = {
    result: 'OK',
}

type validationMissing = {
    result: 'MISSING_FIELDS',
    details: ValidationResultMissingFieldsDetails,
}

type validationDuplicated = {
    result: 'DUPLICATED_FIELD',
    details: ValidationResultDuplicatedField,
}

type Validation = ValidationOK | validationMissing | validationDuplicated;

const ok: Validation = {
    result: 'OK',
}

const missing: Validation = {
    result: 'MISSING_FIELDS',
    details: ['x'],
}

const duplicated: Validation = {
    result: 'DUPLICATED_FIELD',
    details: 'hello',
}

function handle(v: Validation) {
    if (v.result === 'OK') {
        // no details
    } else if (v.result === 'MISSING_FIELDS') {
        // [string]
        const m = v.details[0];
    } else if (v.result === 'DUPLICATED_FIELD') {
        // string
        const d = v.details;
    }
}

TypeScript 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

Grab a parameter from the URL and insert it into an element before smoothly scrolling down to that

On a button, I have a URL that looks like this: www.mywebsite.com/infopage?scrollTo=section-header&#tab3 After clicking the button, it takes me to the URL above and opens up the tab labeled tab3, just as expected. However, I would like it to direct m ...

React: The useContext hook does not accurately reflect the current state

I'm currently facing a dilemma as I attempt to unify data in my app. Whenever I click the button, the isDisplay value is supposed to be set to true; even though the state changes in my context file, it does not reflect in the app. Thank you for your ...

Troubleshooting error "is not assignable to type..." when simulating global fetch using TypeScript

I am encountering an issue with the "global.fetch" part and cannot seem to figure out why. Despite following the standard procedure, I am still facing this TS2322 error. I am seeking assistance to understand why this error is occurring. I am open to sugges ...

Passport.js consistently returns an unauthorized status for every request, even when a valid token is provided, or it author

I am facing issues with my Passport.js functions not authenticating users properly. When I use the current form, it always returns "unauthorized" for all requests: import passport from 'passport' import passportJWT from 'passport-jwt' ...

Prevent a specific file from being compiled during karma testing sessions

For my Angular application using angular-cli with Karma, I am facing an issue where a specific file needs to be excluded from compilation during unit tests. The file causing the problem is mentioned in the error message, indicating that it cannot be compi ...

How can I implement a dynamic progress bar using Ionic 4?

I am currently working on developing a progress bar that increases by 1% every time the user clicks a button. This is what my HTML code looks like: <ion-button *ngFor="let progress of progress" (click)="add(progress)">Progress</ion-button> &l ...

Error: 'ngForOf' is not recognized as a valid property of the 'tr' element

Since this afternoon, I've been facing a challenge that I can't seem to grasp. The issue lies within a service I created; in this file, there is an object from which I aim to showcase the data in a loop. An error message is displayed: NG0303: C ...

Sharing information from Directive to Component in Angular

Here is a special directive that detects key strokes on any component: import { Directive, HostListener } from '@angular/core'; @Directive({ selector: '[keyCatcher]' }) export class keyCatcher { @HostListener('document:keydo ...

Problem with Gmail Authentication in Nodemailer

I am currently facing an authentication issue while trying to use Nodemailer in a Node.js application to send emails via Gmail. The error message reads "Missing credentials for 'PLAIN'." I have carefully reviewed my code and environment variables ...

Service B is receiving query parameters from Service A in a peculiar object format, leaving us puzzled as to the reason behind this unexpected structure

Issue: Encountered a strange bug when our service A (using laravel php) makes a call to an endpoint in service B (built with nodejs typescript + ajv + nestjs). Further explanation of the issue below. Below is an example of code in service A for constructi ...

Exploring subclasses in TypeScript

When working with TypeScript and defining an interface like the one below: export interface IMyInterface { category: "Primary" | "Secondary" | "Tertiary", } Can we access the specific "sub types" of the category, such as ...

The NestJs project fails to display the updates when using the "tsc" command before running either "npm run start" or "npm run start:dev"

As a beginner in nestjs, I decided to start a tutorial to learn more about it. However, whenever I make updates or changes to my code, I don't see any changes reflected in the results. Can someone please assist me with this issue? Below are my tsconfi ...

Understanding Different Symbols in TypeScript

Can you explain the purpose of symbols in TypeScript to me? As someone familiar with Java, it seems a bit unnecessary to use them alongside an interface declaration. What is the reason for setting symbols in TypeScript? For example, consider the followin ...

The state may be modified, but the component remains unchanged

I've been tasked with implementing a feature on a specific website. The website has a function for asynchronously retrieving data (tickets), and I need to add a sorting option. The sorting process occurs on the server side, and when a user clicks a s ...

Unable to locate TypeScript's before() and after() methods

Having trouble running TypeScript tests with Jest/SuperTest - when running npm test, I encounter the following errors: Which package am I missing or not importing? FAIL test/test.ts ● Test suite failed to run test/test.ts:8:3 - error TS2304: Ca ...

Leveraging (click) Event and routerLink in Angular Button Configuration

I'm currently working on a button that needs to redirect to a new page and save data to a Service simultaneously. The code I have in place looks like this: <button [disabled]="!isValid" (click)="saveToService()" routerLink=&quo ...

Guide to creating JSDoc for a TouchEvent handler

Looking to improve my shorter-js codebase with JSDoc for TypeScript definitions, but hitting a roadblock. I've implemented the on() function using Element.addEventListener, working well so far. However, when passing a TouchEvent as a parameter for an ...

Error: Type '() => () => Promise<void>' is not compatible with type 'EffectCallback'

Here is the code that I'm currently working with: useEffect(() => { document.querySelector('body').style['background-color'] = 'rgba(173, 232, 244,0.2)'; window.$crisp.push(['do', 'ch ...

Ways to redirect to a different page following a successful execution of a mutation in React-query

I am facing an issue where a memory leak warning appears when I redirect to another page after a mutation. Despite trying various methods, I have not been able to find a solution. The specific warning message is: Warning: Can't perform a React state ...

Unable to update a single object within an array using the spread operator

I am currently working on updating an object within an array and have encountered some issues. In my initial code, I successfully updated a specific property of the object inside the array like this: var equipment = this.equipments.find((e) => e.id === ...