Fixed-sized array containing union parameters

One of my programming utilities allows me to create a statically sized array:

export type StaticArray<T, L extends number, R extends any[] = []> = R extends {
  length: L;
}
  ? R
  : StaticArray<T, L, [...R, T]>;

To verify its functionality, I can use it like this:

let myVar: StaticArray<number, 3>;
//  ^? let myVar: [number, number, number]

Now, I am interested in making it work with sum types, but I'm unsure on how to achieve that. I envision the following outcome for this scenario:

let myVar: StaticArray<number, 3 | 2 | 1>;
//  ^? let myVar: [number, number, number] | [number, number] | [number]

Unfortunately, my attempts have been unsuccessful as the StaticArray type seems to stop at the smallest number encountered.

Answer №1

There has been a proposal to allow StaticArray<T, L> the ability to be distributive over unions in L, so that StaticArray<T, L1 | L2> would essentially equal to

StaticArray<T, L1> | StaticArray<T, L2>
.

To achieve this functionality, it is recommended to use a distributive conditional type. By defining a conditional type like T extends U ? V : W where T represents a generic type parameter, TypeScript will automatically distribute across unions within T. If the objective is simply to convert a non-distributive type into a distributive one, it can be encapsulated with a "no-op" distributive conditional type such as T extends any ? ⋯ : never. Even though it may seem insignificant (T always satisfies the condition of any), it effectively distributes over unions.

This results in the following code snippet:

type StaticArray<T, L extends number, R extends any[] = []> =
  L extends any ? R extends { length: L; } ? R : StaticArray<T, L, [...R, T]> : never;

Illustrating that it functions as intended:

let myVar: StaticArray<number, 3>;
//  ^? let myVar: [number, number, number]

let myVar2: StaticArray<number, 3 | 2 | 1>;
//  ^? let myVar2: [number] | [number, number] | [number, number, number]

Note that you can replace the usage of any in T extends any ? ⋯ : never with any value that ensures extension by T. Options include unknown, T, or a constraint (such as number for L).

Link to Playground demonstrating Code 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

Is it considered appropriate to return null in a didReceiveResponse callback function?

In my implementation, I have a callback called didReceiveResponse within a class that extends RESTDataSource. In this method, I return null when the response status is 404. However, due to the typing definition of RESTDataSource.didReceiveResponse, it seem ...

Developing advanced generic functions in Typescript

I am currently working on a Hash Table implementation in Typescript with two separate functions, one to retrieve all keys and another to retrieve all values. Here is the code snippet I have so far: public values() { let values = new Array<T>() ...

Error TS2322: Cannot assign a variable of type 'number' to a variable of type 'string'

Encountered an issue with TS2322 error while attempting to compile my Angular application. The error occurs when using a variable [link] that represents the index number. When declaring this variable, I use: @Input() link!: string; This link is used as ...

Trouble with Typescript in VSCode made easy

Setting up a VSCode environment for working with TypeScript v2.03 has been challenging. Beginning with a simple vanilla javascript snippet that can be tested in node via the integrated terminal. function Person() { this.name = ""; } Person.prototy ...

TypeScript requires that when explicitly specifying the return type of a generator, the `Generator.prototype.return` function must accept

I am utilizing a generator function to serve as a consumer for accumulating strings: function *concatStrings(): Generator<void, string, string> { let result = ''; try { while (true) { const data = yield; result += data; ...

Leveraging default values in generic implementations

Imagine a scenario where the following code is present: type QueryResult<ResultType = string, ErrorType = string> = { result: ResultType, } | { errors: ErrorType, } So, if I want to initialize my result, I can proceed like this: const myResult: ...

How to invoke a method in a nested Angular 2 component

Previous solutions to my issue are outdated. I have a header component import { Component, OnInit } from '@angular/core'; import { Router, NavigationEnd } from '@angular/router'; import { Observable } from 'rxjs/Observable'; ...

Dealing with React and Firebase Authentication Errors: How to Handle Errors for Existing Accounts with Different Credentials

According to the documentation at https://firebase.google.com/docs/auth/web/google-signin#expandable-1, when error.code === 'auth/account-exists-with-different-credential', signInWithPopup() should return an error.email. However, in my specific c ...

There is an error appearing in my .ts code: [ts] The property 'name' is not found in type 'any[]'

While my coding is working fine and data is showing on the page, there seems to be an error occurring in the VSE editor. It is showing something like this: [ts] Property 'name' does not exist on type 'any[]'. This is a snippet of my ...

What is the best way to assign an index signature to a plain object?

Currently, I have this object: const events = { i: 'insert', u: 'update', d: 'delete' }; I am struggling to assign an index signature to the object. When I try the following: export interface EventsSignature { [key: ...

Customize TypeScript Generic Types in Method<T> Extending from a Base Class<T> as a Backup Plan

In my example, I have created an Angular Service with multiple Generic Types that can be overridden through the methods. The issue I am encountering revolves around = versus extends and how it affects typing in the arguments. Strangely, using = works perfe ...

Having difficulty maintaining trailing zeroes in decimals after converting to float in Angular

I need assistance with converting a string to float in Angular. Whenever I use parseFloat, it seems to remove the zeros from the decimal values. How can I ensure that these zeros are retained with the numerical values? The example below should provide more ...

Bringing Typescript functions into the current module's scope

Is it possible to import and reference a module (a collection of functions) in typescript without the need for the Module. prefix? For instance: import * as Operations from './Operations'; Can I access Operations.example() simply as example()? ...

Saving the current state of a member variable within an Angular 2 class

export class RSDLeadsComponent implements OnInit{ templateModel:RSDLeads = { "excludedRealStateDomains": [{"domain":""}], "leadAllocationConfigNotEditables": [{"attributeName":""}] }; oldResponse:any; constructor(private la ...

What is the best way to retrieve the current height in VueJS using the Composition API?

I am utilizing a Ref to preserve the current height of the active element. My goal now is to transfer this height to the subsequent element that gets clicked on. <script lang="ts" setup> import { ref, reactive } from "vue"; defin ...

Issue with page break functionality during print preview

div.pagebreak { page-break-after: always; page-break-inside: avoid; } HTML <!-- Page separator --> <div class="pagebreak" style="float: none;"><hr class="hidden-print" /></div> <app-mud-chec ...

Having trouble establishing a connection with the C# Controller when processing the frontend request

Having trouble implementing the Search by siteId functionality using typescript and C#. The issue arises when trying to connect to the C# controller from the frontend request. The parameter I need to pass is siteId. Below is the code snippet: HTML: ...

What's the best way to refactor the `await nextEvent(element, 'mousemove')` pattern in my code once it is no longer necessary?

Within my React component, the code includes the following: class MyComponent extends React.Component { // ... trackStats = false componentDidMount() { this.monitorActivity() } componentWillUnmount() { this.trackStat ...

Issue with Ionic Capacitor React & Typescript build process for Firebase Functions

Recently, I've been working on a cutting-edge Ionic Capacitor React application that utilizes Typescript with a Firebase backend. While everything has been running smoothly so far, I encountered some challenges when trying to build Firebase Functions. ...

Dependencies exclusively for NPM post-installUnique Rewrite: "N

I have been using git to distribute an internal TypeScript NPM package. To avoid cluttering my repository with build files, I have implemented a postinstall action to build the package upon installation: "postinstall": "tsc -p tsconfig.json& ...