The rest parameter is required to be an array type when passing a tuple type

I have a custom type that distinguishes between tuples (exact length) and arrays. I'm looking to leverage this distinction to automatically infer parameter types:

type ANumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;

type IsTuple<Type> = Type extends readonly unknown[] ? Type['length'] extends ANumber ? true : false : false;

function fn<T extends Record<keyof T, unknown>>() {
  return function withConfig(config: {
    [K in keyof T]: IsTuple<T[K]> extends true
      ? (...params: T[K]) => void
      : (param: T[K]) => void
  }) {};
}

fn<{ tupleType: [number, number], arrayType: number[] }>()({
  tupleType: (one, two) => {},
  arrayType: (arr) => {}
})

The function call executes successfully, and one, two, and arr are correctly inferred. However, the line ? (...params: T[K]) => void triggers an error:

A rest parameter must be of an array type

But wait... isn't a tuple technically an array type too? How can I guide the compiler to understand this distinction?

Playground

Answer №1

If you encounter a scenario where you have a generic type XXX that you believe can be assigned to type YYY, but the compiler does not recognize it (resulting in an error), you can usually resolve this by substituting XXX with Extract<XXX, YYY> utilizing the the Extract<T,U> utility type.

The compiler can comprehend that Extract<XXX, YYY> is assignable to both XXX and YYY. Later on, when the specific generic type is indicated, then Extract<XXX, YYY> will essentially equal whatever XXX resolves to, assuming your initial assertion that XXX could be assigned to YYY was accurate.

In your case, if you have T[K] which you know can be assigned to an array type such as readonly unknown[], even though the compiler does not recognize it (as it doesn't analyze higher-order types to understand that IsTuple<T> extends true indicates that T is an array). You can replace T[K] with

Extract<T[K], readonly unknown[]>
:

function fn<T extends Record<keyof T, unknown>>() {
  return function withConfig(config: {
    [K in keyof T]: IsTuple<T[K]> extends true
    ? (...params: Extract<T[K], readonly unknown[]>) => void  // okay
    : (param: T[K]) => void
  }) { };
}

This approach should work, and the rest of your code should operate in a similar manner as before.

Check out the Playground link for the 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

Send a variable from a next.js middleware to an API request

I've been attempting to pass a middleware variable to my API pages via "req" but have encountered some issues Even after trying to send the user token to pages using "req", it consistently returns null The middleware file in question is: pages/api/u ...

Oops! The formGroup function in Angular 5 requires an instance of a FormGroup

While working with Angular 5, I encountered an error in this basic form. Here is the issue: Error Message: EditVisitanteDialogComponent.html:10 ERROR Error: formGroup expects a FormGroup instance. Please pass one in. Example: > > &l ...

How can I convert select all to unselect all in ngmultiselect within the Angular framework?

My attempt at resolving the issue is as follows, but it seems to be malfunctioning: (<HTMLInputElement>(<HTMLInputElement>document.getElementById("Categorydropdown")).children[0].children[1].children[0].children[0].children[0]).check ...

flushMicrotasks does not function properly in conjunction with the image.onload event

Working on an Angular project, I'm currently developing an object with an image field. The method responsible for loading the image returns a promise that resolves in the onload function of the image. When trying to test this method using the flushMi ...

How can I assign the output of a function to a variable within a class in Angular?

Is there a way for the Army class to automatically update its CP property with the sum of CP values from all Detachments in the Detachment class? In the Army class, the CP property should reflect the total CP value from all Detachments and be accessible t ...

Extract an object array from the object and combine it into one cohesive unit

I am seeking assistance to consolidate data from an array of objects into a single array. Here is the current response I have: [ { "title": 'sample name of title 1', "isDeleted": false, "debates": [ ...

How to Utilize FormData in IE9 with Angular 5 and TypeScript Without Ajax or jQuery

Within my Angular 5/Typescript application, there is an UploadFile component structured as follows: component.html .... <form #formUpload id="formUpload"> <input type="file" class="input-file-ghost" (change)="onChangeFile($event.target.files) ...

Correcting Typing Errors in TypeScript

My current challenge involves a method that is consuming data from an external API: public async getStatus(id: string): Promise<APIRes | undefined> { try { const result = await getRequest(`${this.URL}/endpoint/${id}`) const respo ...

When I utilize a component to create forms, the React component does not refresh itself

One of the components I am working with is a form handling component: import React, { useState } from "react"; export const useForm = (callback: any, initialState = {}) => { const [values, setValues] = useState(initialState); const onCha ...

Leveraging Angular 4-5's HttpClient for precise typing in HTTP requests

Utilizing a helper service to simplify httpClient calls, I am eager to enforce strong typing on the Observable being returned. In my service where I utilize the api Service and attempt to obtain a strongly typed observable that emits: export class ApiU ...

Redux Saga effect does not have a matching overload for this call

Encountering an error in my Redux Saga file, specifically when using the takeLatest() Saga effect. TypeScript is throwing the following error: (alias) const getMovies: ActionCreatorWithoutPayload<string> import getMovies No overload matches this call ...

Removing redundant names from an array using Typescript

My task involves retrieving a list of names from an API, but there are many duplicates that need to be filtered out. However, when I attempt to execute the removeDuplicateNames function, it simply returns an empty array. const axios = require('axios&a ...

Strategies for defining a ReactNode with optional props

I've been struggling for a while now trying to solve this issue without any success. I have a component that accepts two child nodes in the following structure: <SharedTwoColumns outer={{ className: "mt4 mb4" }} gap={<div className ...

Deploying React with Firebase Cloud Functions in Typescript encounters deployment issues

In my project, I want to incorporate React app in Typescript hosted on Firebase hosting Firestore Firebase functions in Typescript Encountering an issue during deployment. It's easily replicable (Just skip firestore and firebase hosting initializati ...

What are the reasons behind memory leaks and decreased rendering speed when I exit and then reopen a React component (specifically Material-Table)?

I have been working on a basic React example for learning purposes, and I incorporated the use of material-table in one of my components. However, I noticed that each time I change pages and reopen the component (unmount and mount), the rendering speed of ...

The URL is reverted back to the previous address

Currently in the process of developing an Angular application, I've encountered a minor visual issue. On one of the pages, there is a ReactiveForm implemented, but whenever I navigate to that page, the URL reverts back to the previous one (even though ...

Cache items in a list that require a callback function

I am facing a challenge with a list of checkboxes that I display on my website. Every time I click on one checkbox, it is added or removed from a selection that I maintain. This process is handled by a callback function. The issue arises when the number of ...

Error message: Issue with TypeScript and cleave.js - 'rawValue' property is not found on type 'EventTarget & HTMLInputElement'

I am encountering an error with the onChange event while implementing cleave in typescript. TypeScript is throwing an error indicating that 'rawValue' is not present in event.target. Here is my code: import React, { useCallback, useState, useEff ...

Is there a point in bundling NPM packages if they are ultimately going to be bundled by the project

I'm in the process of creating a TypeScript package for publication on NPM. My plan is to utilize this package in upcoming web development endeavors, most likely utilizing Vite. As I look ahead to constructing a future website with this module, I am c ...

Is there a method to automatically select or deselect a checkbox based on the incoming value in Angular?

When new data comes in, the table gets populated and I can't specify that "A" should be checked while "D" shouldn't. re(ref: getrefactormodel, count:number){ let data= this.fb.group({ word_to_rename: [ref.word_to_rename, Vali ...