In order for the expansion parameter to be successfully used, it must be either of tuple type or passed to the

    const myFunction = function(arg1: number, arg2: number, arg3: number) {}
    const myFunction1 = function() {}

    const obj = { myFunction, myFunction1 };

    type FuncType = typeof obj;

    function executeFunction<T extends keyof FuncType>(key: T, ...args: Parameters<FuncType[T]>) {
      const func: FuncType[T] = obj[key];
      func(...args);
      // error: The expansion parameter must have a tuple type or be passed to the rest parameter.
    }

This error occurs when calling func(...args);: The expansion parameter must have a tuple type or be passed to the rest parameter.

How can I resolve this issue?

Answer №1

When aiming to quickly overcome an error, one method is to utilize the `any` type to bypass type checking for `fn`:

function test2<K extends keyof Type>(key: K, ...args: Parameters<Type[K]>) {
    // Let the compiler know it's just 'any'
    const fn: any = o[key];
    fn(...args); // no issues
}

However, opting for this approach means relinquishing compiler-verified type safety by resorting to `any` or type assertions where the burden of type checking shifts from the compiler to the developer.


If seeking for the compiler to comprehend the underlying logic of the process, then a refactoring of the type of `o` to something that accurately represents it at the type level is necessary. The typechecker struggles to deduce that `Parameters<Type[K]>` is a suitable argument for a function of type `Type[K]`. Since `Type[K]` is viewed as a union of functions rather than a single generic function type, the compiler is unable to translate the form `{ test(a: number, b: number, c: number): void; test2(): void }` into something meaningful. `Parameters<Type[K]>` pertains to a generic conditional type, a concept elusive to the compiler which fails to interpret the identifier "Parameters" or reason abstractly with it.

The limitation of TypeScript in deducing abstract correlations within data structures is highlighted in microsoft/TypeScript#30581 specifically concerning correlated unions. The recommended resolution involves refactoring to a distinct form of generic indexed accesses within a mapped type as elucidated in microsoft/TypeScript#47109.

Refactoring the example code entails:

function test3<K extends keyof Type>(key: K, ...args: Parameters<Type[K]>) {
    const _o: { [P in keyof Type]: (...args: Parameters<Type[P]>) => void } = o;
    const fn = _o[key];
    fn(...args); // no issues
}

In this scenario, `o` is reassigned to `_o` following a mapped type structure { [P in keyof Type]: (...args: Parameters<Type[P]>) => void }. The assignment approval is due to the compiler perceiving the structural identity between `o` and `_o`. Even though structurally identical, they are represented distinctively. The mapped type explicitly captures the generic relationship between an arbitrary property of `_o` and its function structure. Indexing into `_o` with `key` construes a direct function type rather than a union of functions, specifically `(…args: Parameters<Type[K]>) => void` which easily handles `...args`.

This showcases how TypeScript backs this function type while retaining certain type safety assurances. This particular refactoring involves minimal effort or added code but extensive refactorings may potentially complicate code comprehension for human developers maintaining it. The choice between quick/easy/unsafe and slow/complex/safe approaches depends on the specific use case.


View the code in TypeScript Playground

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

What issues can trailing white space cause in TypeScript coding?

While I understand that linting is the reason for this, why are trailing spaces considered problematic? I plan to disable this feature in tslint.json, but before I make that change, I want to ensure I'm not making a mistake. Visual Studio Code alert ...

Creating a nested observable in Angular2: A step-by-step guide

Currently, I am exploring a new approach in my Angular2 service that involves using observables. The data source for this service will initially be local storage and later updated when an HTTP call to a database returns. To achieve this dynamic updating of ...

Is it possible to remove a complete row in Angular 2 using Material Design

JSON [ { position: 1, name: 'test', value: 1.0079, symbol: 'HHH' }, { position: 2, name: 'test2', value: 4.0026, symbol: 'BBB' }, { position: 3, name: 'test3', value: 6.941, symbol: 'BB' }, ...

Using TypeScript to filter and compare two arrays based on a specific condition

Can someone help me with filtering certain attributes using another array? If a condition is met, I would like to return other attributes. Here's an example: Array1 = [{offenceCode: 'JLN14', offenceDesc:'Speeding'}] Array2 = [{id ...

Error message is not shown by React Material UI OutlinedInput

Using React and material UI to show an outlined input. I can successfully display an error by setting the error prop to true, but I encountered a problem when trying to include a message using the helperText prop: <OutlinedInput margin="dense&quo ...

A step-by-step guide on sending a fetch request to TinyURL

I have been attempting to send a post request using fetch to tinyURL in order to shorten a URL that is generated on my website. The following code shows how I am currently writing the script, however, it seems like it's not returning the shortened URL ...

Exploring the potential of lazy loading with AngularJS 2 RC5 ngModule

I am currently utilizing the RC5 ngModule in my Angular project. In my app.module.ts file, the import statements and module setup are as follows: import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/plat ...

The Challenge of Iterating Through an Array of Objects in Angular Components using TypeScript

Could someone please explain why I am unable to iterate through this array? Initially, everything seems to be working fine in the ngOnInit. I have an array that is successfully displayed in the template. However, when checking in ngAfterViewInit, the conso ...

Exploring the power of RxJs through chaining observers

In my Angular application, I am utilizing Observables to set up a WebSocket service. Currently, I have the following implementation: readwrite(commands: command[]) : Observable<response[]>{ const observable = new Observable((observer)=>{ ...

import component dynamically from object in Next.js

Currently, I have a collection of components that I am aiming to dynamically import using next/dynamic. I'm curious if this is achievable. Here's the object in interest: // IconComponents.tsx import { Tick, Star } from 'components ...

Visual Studio Code unable to locate source maps for typescript debugging

Looking for some help debugging a basic Hello World TypeScript file. Whenever I try to set a breakpoint, it seems like VS Code is having trouble locating the source map, even though it's saved in the same directory. I'm using Chrome as my browser ...

Transitioning a JavaScriptIonicAngular 1 application to TypescriptIonic 2Angular 2 application

I am currently in the process of transitioning an App from JavaScript\Ionic\Angular1 to Typescript\Ionic2\Angular2 one file at a time. I have extensively researched various guides on migrating between these technologies, completed the A ...

Deleting a file from the assets folder in Angular for good

I am attempting to permanently delete a JSON file from the assets folder using my component. Despite trying to use HttpClient, I encounter no errors but the file remains undeleted. constructor(http: HttpClient){} remove() { this.http.delete('assets ...

Data cannot be transferred to a child element unless it has been initialized during the definition phase

Passing an array data from parent to child component has brought up some interesting scenarios: parent.component.html: <child-component ... [options]="students" > </child-component> Status I: Setting the array on definition ...

Error: Name 'AudioDecoder' could not be located

In my current project using React and TypeScript with Visual Studio Code 1.69.2 and Node 16.15.1, I encountered an issue. I am attempting to create a new AudioDecoder object, but I keep getting an error message stating "Cannot find name 'AudioDecoder ...

The element is implicitly assigned the 'any' type due to the inability to use an expression of type to index the element

Check out my TS playground here // I have colours const colors = { Red: "Red", Blue: "Blue", Green: "Green" } type TColor = keyof typeof colors; // Some colours have moods associated with them const colorsToMood = { ...

Adding an active class on a selected chat list item in Angular - here's how!

We are currently developing a chat component where users can click on the left side chat item to open messages with the selected user. We have implemented an active class that changes the color of the selected chat list item. Our goal is to apply the activ ...

Error: An unexpected token < was caught in the TypeScript Express code

Using TypeScript to compile and run an Express server that simply serves an HTML file. However, encountering an error in the response under the network tab in Chrome for app.js: Uncaught SyntaxError: Unexpected token '<' Below is the server c ...

Using ngFor directive to iterate through nested objects in Angular

Receiving data from the server: { "12312412": { "id": "12312412", "something": { "54332": { "id": "54332", "nextNode": { "65474&q ...

Using a SharedModule in Angular2: A Guide

I have a single Angular2 component that I need to utilize across multiple modules. To achieve this, I created a SharedModule as shown below: import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-bro ...