Is it possible for a const type parameter to capture varargs?

TypeScript 5.0 has recently introduced a new feature known as const type parameters. Can varargs be captured using this type parameter?

Let's take a look at the following function attempting to achieve this:

function insertIf<const V extends any[]>(condition: boolean, ...value: V): V | readonly [] {
    if (condition) {
        return value;
    } else {
        return [];
    }
}

However, it seems that the return type always ends up being any[] | readonly [], regardless of the actual arguments provided to the function.

For instance, consider calling

insertIf(true, { s: 'a' }, { s: '?'})

Answer №1

To ensure proper functionality, it is recommended to adjust the constraint on V and switch from any[] to a readonly array type, such as readonly any[]:

function insertIf<const V extends readonly any[]>(
    condition: boolean, ...value: V
): V | readonly [] {
    if (condition) { return value; } else { return []; }
}

const x = insertIf(true, { s: 'a' }, { s: '?' });
// const x: readonly [] | readonly [{ readonly s: "a"; }, { readonly s: "?"; }]

In regards to the explanation of microsoft/TypeScript#51865, pertaining to the implementation of const type parameters, it mentions:

If a const type parameter is restricted to an array type, it is essential for that array type to include a readonly modifier; otherwise, inferences for the type parameter will not meet the constraint.

Therefore, with your original version:

function insertIf<const V extends any[]>(
    condition: boolean, ...value: V
): V | readonly [] {
    if (condition) { return value; } else { return []; }
}

const x = insertIf(true, { s: 'a' }, { s: '?' });
// const x: any[] | readonly []

The compiler actually seeks to infer V as

readonly [{ readonly s: "a"; }, { readonly s: "?"; }]
here, akin to utilizing a const assertion. However, this type is not compatible with any[]; readonly arrays have fewer known methods compared to normal read-write arrays.

Consequently, the inference process fails, leading the compiler to revert to the constraint of any[], which passes the type check and may result in seemingly silent code failure.


This has been acknowledged as a source of confusion and has previously been reported as a bug, as seen in microsoft/TypeScript#51931. It would be beneficial if the compiler could provide some form of warning indicating that the const modifier might not function optimally, but as of now, the behavior aligns with its intended design, with the solution being to incorporate the readonly modifier.

Playground link to code

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

Building interactive forms in Angular 6

I want to design a dynamic form that creates a new form when the AddNew button is clicked. In my TypeScript (ts) file, I have the following code: addinfoForm: FormGroup; infoNameList: FormArray; infoModel: Productdetail; constructor(private fb ...

Show the values of an array if the array name matches the string name

Is there a way to dynamically display the values of an array based on a matching string in Angular 4 or 6? Let's say we have two arrays, A and B: A = ['aaa','arrr','aeee','aqqqq','awwww','axxxx& ...

Implementing NGRX sequential actions triggered from a component

I am attempting to send sequential requests to the ngrx-store in order to save two different entities in randomly chosen MongoDB collections. The challenge lies in needing a response from the first ngrx-store effect in order to utilize the data in another ...

Angular 6: A class with no 'default' modifier must explicitly specify a name

I am encountering this error in my ts.file, as I delve into the world of Angular/Ionic. Can anyone help identify the possible reasons for this? I have attempted multiple solutions to address it, but unfortunately, none have proven successful. import { Co ...

"Error: Import statement must be used within a module" encountered in TypeScript (with nodemon) and Node.js (running in Docker)

Within the server directory of my web application written in TypeScript, there is a nodemon command used to automatically restart the code after changes are made. The command looks like this: nodemon dist/index.js However, upon running it, an error is enc ...

Gulp is failing to generate bundled files

I'm having trouble generating my bundle files. Everything was running smoothly until I attempted to update to gulp4, and now that I've reverted back to gulp3, the files are not appearing in my dist directory. Gulp successfully created the files i ...

Unable to properly display date formatting in AG-Grid using the Angular date pipe

Currently, I am utilizing ag-grid in conjunction with Angular 8. Within my table, there is a column where my intention is to exhibit dates in a concise format. In order to achieve this, I opted to utilize the Angular date pipe. However, it appears that the ...

Combine iron-page and bind them together

Recently, I've started learning about Polymer and I want to bind together paper-tabs and iron-pages so that when a tab is clicked, the content loads dynamically. After going through the documentation, this is what I have tried: <app-toolbar> ...

Ensure that every member of an object adheres to a particular generic interface in some capacity

Can a TypeScript index signature type be used to enforce that every index adheres to a generic interface? I want to define code like this: interface HasState<T> { state : T; } interface ModuleDefinition { [moduleName : string] : <T>HasSta ...

Can you explain the significance of <any> when used before a Typescript class constructor parameter?

Currently, I am immersing myself in the Angular - Testing documentation. While going through the section on testing asynchronous services (specifically HTTP services), I came across a class constructor containing an <any> right before the passed argu ...

Updating the view of an HTML page in Angular after a set period of time can be achieved by

I am facing an issue while trying to dynamically display a router link based on a certain condition. The goal is to show the routerLink name within the div section if a specific condition is met. Initially, when I check {{isNameAvailable}}, it returns fals ...

What is preventing this from being a function?

It appears that the authenticationProvider is missing for some reason. @autoinject() export class ProviderManager implements AuthenticationManager { constructor( private container: Container ){ } public authenticate( creds: Credentials ): Promis ...

Attempting to deactivate the submit button in the absence of any input

As a beginner trying to work with typescript and html, I am facing an issue with disabling the submit button when a user fails to enter a part number. The error message I am getting is "Cannot find name 'partNumber'". Any advice or guidance on th ...

What is the method for comparing a value in TypeScript that does not match a given value?

I am new to scripting languages and encountered an issue while using enums with if-else statements in TypeScript. To work around this problem, I have decided to use switch-case instead of if-else conditions. Despite trying !== and !===, they do not seem t ...

Is there a way to operate both websocket and http methods concurrently on a server in Typescript?

I have a question regarding running a websocket server with the route "ws://localhost:port" using the 'ws' library. It requires the app instance of 'express' and also features http routes such as "http://localhost:port/auth/login". I am ...

Is there a way to design a function that can accept arrays as parameters if necessary?

Looking to create a function with the following structure: const updateNodeTypeByIndex = (index: Vec2 | Vec2[], type: NodeType | NodeType[]) => { if (index instanceof Array && type instanceof Array){ // deal with array parameters ...

The implementation of race in React Redux Saga is proving to have negligible impact

I have implemented the following saga effect: function* loginSaga() { const logoutTimeoutCreationDate: string | null = yield localStorage.getItem('logoutTimeoutCreationDate'); let logoutTimeout: number; if (!logoutTimeoutCreationDate || + ...

Resolving the non-null assertion error in TypeScript and React: A step-by-step guide

My code snippet is as follows: type ItemProps = { status?: string; } <Items status={status!} /> // encountering an error with a warning about forbidden non-null assertion // @typescript-eslint/no-non- ...

Do you have to use "new MyClass" when initializing an array in Typescript?

In this example, I am creating a class called Person. I have opted to use a class instead of a type alias because the constructor for this class is more complex and contains functions. class Person { name: string; age: number; constructor(name ...

As I attempt to log in, the GitHub API is sending back a message stating that authentication

const fetchUser = async () =>{ let usernameValue : any = (document.getElementById('username') as HTMLInputElement).value; let passwordValue : any = (document.getElementById('password') as HTMLInputElement).value; const ...