Working with an arbitrary number of arguments in TypeScript

Looking for a way to pass an arbitrary number of arguments with different types into a function and utilize those types, similar to the following:

function f<A>(a: A): A;
function f<A, B>(a: A, b: B): A & B;
function f<A, B, C>(a: A, b: B, c: C): A & B & C;
function f<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;

function f(...args: any[]) {
    return Object.assign({}, ...args);
}

var smth = f({ x: 1 }, { y: 2 }, { z: 3 });
var res = smth.x + smth.y + smth.z;

To avoid repeating these declarations due to needing an arbitrary number of parameters, I aim to consolidate them into a single declaration like:

function f<...T>(args: [...T]): &<...T>;

However, this syntax is incorrect. Is there a proper way to rewrite this structure?

PS: The same question in Russian.

Answer №1

Revision for Version 3.0

Although the initial answer was accurate, there have been changes in TypeScript since then. In typescript 3.0, it is now possible to utilize tuples in rest parameters to capture the type of arguments within a tuple.

type UnionToIntersection<U> =
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

function f<A extends any[]>(...args: A): UnionToIntersection<A[number]> { return null! }
var smth = f({ x: 1 }, new A(), new B());  // will be of type  A & B & { x: number; }

Initial Response

While Proposal: Variadic Kinds could potentially aid in this situation as suggested by others, there are workarounds available for your specific scenario.

If we define the function signature with a single type argument, we can achieve a union type of the arguments:

function f<A>(...args: A[]): A {}
var smth = f({ x: 1 }, { y: 2 }, { z: 3 });
typeof smth = {
    x: number;
    y?: undefined;
    z?: undefined;
} | {
    y: number;
    x?: undefined;
    z?: undefined;
} | {
    z: number;
    x?: undefined;
    y?: undefined;
}

An issue arises when using a class instead of an object literal as the compiler fails to infer the union and generates an error. By omitting the rest parameter (...) and simply utilizing an array, the compiler deduces a union of the parameter type:

function f<A>(args: A[]): A { /*…*/}
var smth = f([{ x: 1 }, new A(), new B()]); 
typeof smth == A | B | {
    x: number;
}

To convert the union into an intersection, conditional types can be employed (refer to this for additional information)

type UnionToIntersection<U> = 
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

function f<A>(args: A[]): UnionToIntersection<A> {
    return Object.assign({}, ...args);
}

class A { z: number }
class B { y: number }

var smth = f([{ x: 1 }, new A(), new B()]); // will result in type  A & B & { x: number; }
var res = smth.x + smth.y + smth.z;

We trust that this has provided a helpful workaround until the inclusion of variadic kinds.

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 advisable to include auto-generated files in an npm package upon publication?

I have a TypeScript NPM package where my build process compiles all *.ts files into myLib.d.ts, myLib.js, and myLib.js.map. In order for my NPM package to function properly, it requires the src/*.ts files as well as the auto-generated myLib.* files. Howe ...

How to update nested properties in Typescript using bracket notation

Imagine there is an interface and object with nested properties as shown below: interface Iobj { a: { a2:string }; b: string; } const obj: Iobj = { a:{ a2: "hello" } b: "world" }; Now let's say we have strings that ...

Encountering an issue with importing an enum: An error is triggered stating 'Variable implicitly has type 'any' in certain areas where its type remains undetermined.'

When I define simple enums in the same file, everything works fine. However, exporting/importing them causes numerous compilation errors related to types. It seems like the issue only arises when defining enums in a separate file, pointing towards a proble ...

Numerous toggle classes available

Having the following HTML inside a <span> element: <span (click)="openLeft()"></span> A method in a @Component sets a boolean variable like so: private isOpen: boolean; openLeft() { this.isOpen = !this.isOpen; } To toggle classes ...

Storing the state of DevExtreme DataGrid in Angular

Currently, I have integrated the DevExtreme DataGrid widget into my Angular application. Here is a snippet of how my DataGrid is configured: <dx-data-grid id="gridContainer" [dataSource]="employees" [allowColumnReordering]="true" [allo ...

Passing Selected Table Row Model Data to Backend in Angular 7

My goal is to send the selected data in a table row, which I select through a checkbox, to the server. However, I'm unsure about how to handle this via a service call. While I have the basic structure in place, I need assistance with sending the items ...

Tips for organizing an NPM package containing essential tools

Currently facing the challenge of creating an NPM package to streamline common functionality across multiple frontend projects in our organization. However, I am uncertain about the correct approach. Our projects are built using Typescript, and it seems th ...

Prisma : what is the best way to retrieve all elements that correspond to a list of IDs?

I'm currently implementing Prisma with NextJs. Within my API, I am sending a list of numbers that represent the ID's of objects in the database. For example, if I receive the list [1, 2, 12], I want to retrieve the objects where the ID is eithe ...

How can TypeScript generics be used to create multiple indexes?

Here is an interface snippet: interface A { a1: { a11: string }; a2: { a21: string }; a3: { a31: string }; } I am looking to create a generic type object with indexing based on selected fields from interface A. Here is the pseudo-code exampl ...

Guide on validating a dropdown using template-driven forms in Angular 7

Having trouble validating a dropdown select box, possibly due to a CSS issue. Any suggestions on how to fix this validation problem? Check out the demo here: https://stackblitz.com/edit/angular-7-template-driven-form-validation-qxecdm?file=app%2Fapp.compo ...

the input parameter is not being passed to the component

I need assistance with creating an inline input edit component. The component is loading correctly, but it seems like the @Input() variables are always returning undefined. index.html ... <app-inlineinput [name]="username" [fi ...

Having difficulties in TypeScript identifying types within a project containing multiple node_modules directories

I am currently in the process of transitioning a codebase from Flow to TypeScript. I am encountering an issue with the error message Cannot find module 'SOME DEPENDENCY' or its corresponding type declarations.ts(2307) for several dependencies tha ...

Issue: Unable to call method "call" as the model "Model" has not been initialized within a Sequelize instance. Kindly ensure that "Model" is added to a Sequelize instance before attempting to use the "call" method

Author.ts import {Table, Model, Column, DataType} from 'sequelize-typescript' @Table export class Author extends Model<Author> { constructor(){ super(); } @Column(DataType.STRING) fname: string @Column(DataType.STRING) lname: strin ...

Keeping track of important dates is ineffective using the calendar

I am facing an issue with developing a calendar that marks events on the correct dates. I am receiving the dates in the following format in PHP [ { "status": "OK", "statusCode": 200, "statusMensagem": & ...

Creating React Context Providers with Value props using Typescript

I'd prefer to sidestep the challenge of nesting numerous providers around my app component, leading to a hierarchy of provider components that resembles a sideways mountain. I aim to utilize composition for combining those providers. Typically, my pro ...

Tips for properly narrowing a function parameter that includes "an object key or a function"

Working on a function to retrieve a property using either a string key or a callback, I've encountered an issue with TypeScript narrowing the type parameter. Here is the function in question: function get<T, V>(value: T, fn: (value: T) => V) ...

Unit testing in Angular 2+ involves testing a directive that has been provided with an injected window object

Currently, I am faced with the challenge of creating a test for a directive that requires a window object to be passed into its constructor. This is the code snippet for the directive: import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit ...

What methods can be used to test scss subclasses within an Angular environment?

Exploring different background colors in various environments is a task I want to undertake. The environments include bmw, audi, and vw, with each environment having its own unique background color. Need help writing an Angular test for this? How can I mod ...

Enhancing the appearance of the Mui v5 AppBar with personalized styles

I am encountering an issue when trying to apply custom styles to the Mui v5 AppBar component in Typescript. import { alpha } from '@mui/material/styles'; export function bgBlur(props: { color: any; blur?: any; opacity?: any; imgUrl?: any; }) { ...

Tips on displaying a spinner only when data is retrieved from an Http service

How can I ensure that a spinner is only shown during an HTTP service call and dismissed when my component receives data? To address this issue, I implemented a cache service to store data fetched from the HTTP service for future use. However, I want to sh ...