What sets apart an array of union type from a union array type?

Take a look at the following code snippet:

type unionType = (A | B)[]
type unionArr = A[] | B[]

Can you spot any distinctions between these two choices?

Answer №1

There is a distinction between (A | B)[] and A[] | B[]. The former represents an array that can contain elements of type A or type B, while the latter represents an array where all elements are either of type A or all elements are of type B.

class A { a = "a" }
class B { b = "b" }

type unionType = (A | B)[]
let ut: unionType;
ut = [new A(), new A()]
ut = [new B(), new B()]
ut = [new A(), new B()] // mixed array is acceptable

let uti = ut[0] // When reading, we get A | B because any type can come out of the array

ut[0] = new B();
ut[1] = new A();

ut.reduce((s, e) => e instanceof A ? e.a + s : e.b + s, "") // okay

type unionArr = A[] | B[]
let uArr: unionArr;
uArr = [new A(), new A()]
uArr = [new B(), new B()]
uArr = [new A(), new B()] // mixed array is not valid

let uArri = uArr[0] // Reading gives us A | B because we are unsure if we have A[] or B[]

// Type discrepancy: We can assign a B into uArr[0] even if it is holding an A[] 
uArr[0] = new B();
uArr[1] = new A(); 

// error This expression is not callable.
uArr.reduce((s, e) => e instanceof A ? e.a + s : e.b + s, "") 

Playground Link

In the case of A[] | B[], the requirement that all array items must be of type A or all of type B is primarily enforced during array assignment, rather than when assigning to individual indexes unfortunately.

Additionally, due to how call signatures work for unions, functions like reduce may become un-callable for A[] | B[], whereas functions like map will function correctly.

Generally, it is recommended to use (A | B)[] unless there are compelling reasons to choose otherwise despite its limitations.

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

React Scheduler by Bryntum

After successfully discovering some functions related to various actions, I find myself still in need of additional functions: Currently, I am utilizing these functions by passing them directly as props to the Scheduler React Component: - onBeforeEventSa ...

Setting up Jest to run in WebStorm for a Vue project with TypeScript can be done through

I am struggling to run all my tests within WebStorm. I set up a project with Babel, TypeScript, and Vue using vue-cli 3.0.0-rc3. My run configuration looks like this: https://i.stack.imgur.com/7H0x3.png Unfortunately, I encountered the following error: ...

Having difficulty in accessing the node modules

As a C#/C++ programmer new to nodejs, I am looking to incorporate typescript into my code. However, when attempting to import modules like fs or stream, I am encountering the following error: Module not found Interestingly, VisualStudio 2017 is able to ...

Observable doesn't respond to lazy loaded module subscriptions

I am trying to understand why my lazy loaded module, which loads the test component, does not allow the test component to subscribe to an observable injected by a test service. index.ts export { TestComponent } from './test.component'; export { ...

Is it possible that an error is triggered when utilizing canActivate or canChildActivate?

A problem has arisen while using canActivateChild or canActivate in the child route. Despite working fine previously, an error is now being thrown: ERROR in src/app/app-routing.module.ts(8,7): error TS2322: Type '({ path: string; redirectTo: string; ...

Guide on navigating to a different page using a function with router link in Angular using TypeScript

Trying my hand at Angualar and Typescript for the first time. I am working on creating a login page where users can move to another page if their credentials are correct. To achieve this, I want to use a function that is triggered by clicking a button. How ...

Unlocking Not Exported Type Definitions in TypeScript

Take a look at this TypeScript code snippet: lib.ts interface Person { name: string; age: number; } export default class PersonFactory { getPerson(): Person { return { name: "Alice", age: 30, } } } ...

How to access the dynamic route's path in Next.js when using Server Components?

Obtaining the dynamic route path in a Next JS server component poses a challenge. This task is simple when working with client components. If you are working on src/app/[id]/page.tsx "use client"; import { usePathname } from "next/navigatio ...

Obtain an instance of a class within a function that is contained within an instance object in TypeScript/Angular

There is a separate object responsible for managing a specific dialog box in my application. The challenge lies in accessing the instance of the class, even though the functions are self-explanatory. I attempted to use the conventional method of that = thi ...

Having trouble injecting $resource into my Jasmine unit test

I've encountered an issue while trying to test my self-written service that utilizes $resource. I'm facing difficulties when trying to inject $resource into my test spec. My setup includes Typescript with AngularJS 1.6.x, and here is a snippet o ...

There are no properties associated with this particular data type

As someone who is new to TypeScript, I am encountering two issues with data types. This snippet shows my code: const say: object = { name: "say", aliases: [""], description: "", usage: "", run: (client: ob ...

You cannot call this expression. The type '{}' does not have any callable signatures. Error TS2349

An issue commonly encountered in TypeScript is error TS2349, indicating that sth has no call signatures. Various situations require different solutions, but when working with React's Context, the most effective solution I've discovered is using ...

The push action in NavController is not displaying Google Maps as expected

Trying to display a map upon clicking a button is proving challenging for me. It appears that the function NavController.push() does not work as expected, while NavController.setRoot() does. Despite not encountering any errors, I am unable to identify the ...

Monitoring Object Changes in Angular 4

ETA: I am aware of different methods for monitoring my form for alterations. However, that is not the focus of my inquiry. As indicated by the title, my question pertains to observing changes within an object. The application displayed below is solely for ...

What is the best way to implement multiple templates for a single component?

Is there a way to configure my Home Component based on the user's role? For instance: If the employee is an admin, then the home component should load the template URL designed for admins. Likewise, if the employee is a cashier, then the home compo ...

Custom Mui table sizes - personalized theme

By implementing custom sizes for the Table component in Material UI, I have extended the Table size prop with the following declaration: declare module '@mui/material' { interface TablePropsSizeOverrides { relaxed: true large: true } ...

Utilizing Variables in TypeScript to Enhance String Literal Types

Here are my codes: export const LOAD_USERS = 'LOAD_USERS'; export const CREATE_USER = 'CREATE_USER'; export interface ACTION { type: string, payload: any } I am trying to limit the possible values for ACTION.type to either 'L ...

Issue with default country placeholder in Ionic 6.20.1 when using ion-intl-tel-input

I have successfully downloaded and set up the "ion-intl-tel-input" plugin from https://github.com/azzamasghar1/ion-intl-tel-input, and it is functioning properly. However, I am facing an issue with changing the default country select box placeholder from " ...

Is it possible for ko.mapping to elegantly encompass both getters and setters?

Exploring the fusion of Knockout and TypeScript. Check out this code snippet: class Person { public FirstName:string = "John"; public LastName: string = "Doe"; public get FullName(): string { return this.FirstName + " " + this.Las ...

Click on an element in Angular to toggle it

A function in my codebase is responsible for toggling a specific section within a div element. Currently, there are a total of 3 sections available in the app. The functionality is implemented in the app.component.ts file: show = false; toggle() { ...