The combination of types in a union allows for incorrect assignments of properties from the individual types involved

I'm struggling to grasp the concept of unions in TypeScript. Can someone explain why the following assignment is considered valid? I believed it would only be acceptable for const a = {a:12}, {a:123,b:23}, or {a:12,b:12,c:123}.

type abcd =
    | {
        a: number;
      }
    | {
        a: number;
        b: number;
      }
    | {
        a: number;
        b: number;
        c: number;
      };

const a: abcd = {
    a:123,
    c:234
};

Playground link

If I change c to somethingElse, the assignment is not permitted:

const a: abcd = {
    a:123,
    somethingElse:234 // Error on this line
};

An error message stating:

Type '{ a: number; somethingElse: number; }' is not assignable to type 'abcd'. Object literal may only specify known properties, and 'somethingElse' does not exist in type 'abcd'.(2322)

Answer №1

Summary

To clarify, unions do not guarantee mutual exclusivity. For a workaround on achieving mutual exclusion for types using Union type, never type, and optional property combination, refer to the Work around section in this response.

The functionality of Union type is more akin to an `OR` gate than an `XOR` gate. Essentially, if an object satisfies any of the types in your Union type, it is considered an instance of that Union type.

Consider the following example:

type abcd =
  | {
    a: number;
  }
  | {
    x: number;
    y: number;
  }
  | {
    p: number;
    q: number;
    r: number;
  }
  | {
    x: number;
    y: number;
  };

const APY: abcd = {
  a: 123,
  p: 234,
  y: 1,
};

In this case, as constant `APY` includes enough properties to fulfill the requirements of `{ a: number; }` type within the union, other properties defined in the Union type are allowed.

The limitation imposed by the Union type is that extra properties not within the Union are restricted, while the instance must satisfy one of the types within the union.

Solution

If Union type alone does not provide the desired outcome, combining it with never type can help achieve the intended result:

type abcd =
  | {
    a: number;
    b?: never;
    c?: never;
  }
  | {
    a: number;
    b: number;
    c?: never;
  }
  | {
    a: number;
    b: number;
    c: number;
  };

/*
  Type '{ a: number; c: number; }' is not assignable to type 'abcd'.
  Property 'b' is missing in type '{ a: number; c: number; }' but required in type '{ a: number; b: number; c: number; }'.
*/
const a: abcd = {
  a: 123,
  c: 234,
};

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 method to retrieve and organize all routes and corresponding endpoints in a NestJS application?

When it comes to writing middleware to process requests, I am faced with the issue of excluding certain paths without having to hardcode them manually. To tackle this problem, I came up with an innovative solution: My plan is to create a special decorator ...

The TypeScript compilation is missing Carousel.d.ts file. To resolve this issue, ensure that it is included in your tsconfig either through the 'files' or 'include' property

While trying to build an Angular application for server-side execution, I encountered the following errors: ERROR in ./src/app/shared/components/carousel/interface/Carousel.d.ts Module build failed: Error: /home/training/Desktop/vishnu/TemplateAppv6/src ...

No pathways can be established within Core UI Angular

I've been attempting to use the router link attribute to redirect to a new page, but instead of landing on the expected page, I keep getting redirected to the dashboard. Below is an overview of how my project's structure looks: [![enter image de ...

The TypeScript compiler generates a blank JavaScript file within the WebStorm IDE

My introduction to TypeScript was an interesting experience. I decided to convert a simple JavaScript application, consisting of two files, into TypeScript. The first file, accounts.ts, contains the main code, while the second one, fiat.ts, is a support f ...

What is the timing for the execution of top-level non-export code in TypeScript?

I am currently puzzled about the execution of code in files. Let's say we have a file1.ts with the following content: export interface myInterface {} export function myFunction() {} export const myConst: {} // ... and more exports // top-level non- ...

Tips for creating a mapped type in TypeScript that is based on an array

Is there a way to create a function with dynamic properties? function magic(...propertyNames:string[]): { ????? : any } { .... } Could the returned type have properties listed in propertyName? For instance: type ResultType = {alpha:any, bravo:any}; le ...

Using *ngFor to iterate through a nested collection in an Angular 2 application

I'm currently working on a challenge involving drilling down to iterate over an array within another collection of arrays within an Angular 2 application. To start off, I have set up my component to subscribe to an observable in the ngOnInit lifecycle ...

Tips for Achieving Observable Synchronization

I've encountered a coding challenge that has led me to this code snippet: ngOnInit(): void { this.categories = this.categoryService.getCategories(); var example = this.categories.flatMap((categor) => categor.map((categories) = ...

Oops! We encountered an error: Uncaught (in promise): [object Object]. Angular 5 version is

Trying to implement an upload button using Angular 5, I have the following code in my .ts file: handleFiles(e) { this.file = e.srcElement.files[0]; if (this.file.size > 2097152) { let snackBarRef = this.snackBar.open('Images must ...

Tips for extracting data from an Angular object using the *ngFor directive

https://i.stack.imgur.com/ai7g1.png The JSON structure displayed in the image above is what I am working with. My goal is to extract the value associated with the key name. This is the approach I have taken so far: <span *ngFor="let outlet of pr ...

The changes made to the path property in tsconfig.json are not being registered

A troublesome block of imports has surfaced, as shown in this image: https://i.sstatic.net/lRwK5.png Below is my current configuration in tsconfig.json : { "compilerOptions": { "target": "es5" /* Specify ECMAScript targ ...

Encountering an issue while developing a Discord bot using TypeScript

Hello, I'm currently working on creating a nick command for my discord bot in TypeScript, but I encountered an error. Here is the issue: Error: Expression expected.ts (1109) When I replace const mentionedMember = message? message.mentions.members? ...

`express-validator version 4 is not functioning as expected`

Trying to implement input validation using express-validator v4.3.0 for my express routes, but despite following the documentation, I am unable to get it working correctly. It seems to not detect any errors and also gets stuck in the route. Could it be tha ...

A Typescript interface designed for a higher-order function that returns another function

I am working with a StoryOptions object that includes a property called actionFn. This property, when invoked, will return a function utilizing function currying. The actionFn function must accept an object of type ActionBundle</code and should return ...

When 'Interval.after' is invoked within the library, Luxon throws an error message stating "Invalid Interval."

Encountering a strange issue with Luxon when the Interval.after method is invoked within the library. const interval = Interval.after(dateTime, duration); The following log pertains to the application DateTime__Duration, with the second line representing ...

Webpack is struggling to locate core-js paths when running on Windows operating systems

When running webpack, I am encountering the following errors: ERROR in ./node_modules/core-js/index.js Module not found: Error: Can't resolve './es' in 'pathtoproject\node_modules\core-js' @ ./node_modules/core-js/index. ...

trpc - Invoking a route from within its own code

After reviewing the information on this page, it appears that you can invoke another route on the server side by utilizing the const caller = route.createCaller({}) method. However, if the route is nested within itself, is it feasible to achieve this by ...

Disregard the possibility of React Hook "React.useEffect" running multiple times during execution

I am currently working on a React component that accepts an array of pairs within the props. Each pair consists of: index 0: a function that will be triggered every time the dependencies change, index 1: an array of dependencies. Using the Component & ...

Vue 3 Electron subcomponents and routes not displayed

Working on a project in Vue3 (v3.2.25) and Electron (v16.0.7), I have integrated vue-router4 to handle navigation within the application. During development, everything works perfectly as expected. However, when the application is built for production, the ...

Looking to retrieve HTML elements based on their inner text with queryselectors?

I am looking to extract all the HTML divs that contain specific HTML elements with innerText = ' * ' and save them in an array using Typescript. If I come across a span element with the innerText= ' * ', I want to add the parent div to ...