What is the best way to assign a type based on a variadic type in TypeScript?

TypeScript playground link

For my current project, I am designing a custom route handler creator for Express. The goal is to allow passing arbitrary assertions as initial arguments before invoking the route handler callback. Here's an example of how I envision it:

const myHandler = makeHandler(assertion1(), assertion2(), (data, req, res, next) => {
  // data contains results from the assertions
});

I have managed to achieve some progress in defining the types as needed:

// declaration of Assertion and ReturnTypes

type Assertion<T = unknown> = (req: express.Request) => T;
type ReturnTypes<A extends ReadonlyArray<Assertion>> = {
  [K in keyof A]: ReturnType<A[K]>;
};

function assertion1<T extends object>(arg: T) {
  return () => arg
}

function assertion2() {
  return () => "yes"
}

const a = assertion1({ something: "yes" })
const b = assertion2()

// The expected type here is [{ something: string }, string]
type d = ReturnTypes<[typeof a, typeof b]>

However, when attempting to extend this concept to the arguments of makeHandler, there seems to be an issue where the type of data ends up being unknown[]:

// logic for `makeHandler`

declare function makeHandler<
 Assertions extends Assertion<unknown>[]
>(...assertionsAndCb: [...Assertions, HandlerCb<ReturnTypes<Assertions>>]): void

// 'data' isn't correctly typed here. It should match the same type as `d` above.
makeHandler(assertion1({ hey: "what"}), assertion2(), (data, req) => {
  return { response: {} }
})

I've tried researching similar concepts like zip to improve my function, but I'm struggling to get the types to pass accurately. Is there a missing element or incorrect generic that is preventing proper inference?

Answer №1

A key challenge here lies in the limitations posed by TypeScript when it comes to inferring both generic type arguments and contextual types for callback parameters simultaneously, especially in cases where they seem to be interdependently circular. The ongoing issue can be found at microsoft/TypeScript#47599. While efforts have been made to address these issues (check out microsoft/TypeScript#48538), it is unlikely that a complete resolution will be achieved since TypeScript's inference algorithm doesn't aim to mirror a full unification algorithm. Perhaps future updates may bring about improvements that align better with your intended code behavior, but until then, workarounds are necessary.

In this particular scenario, it appears that you are attempting to achieve simultaneous generic and contextual typing within a tuple structure featuring a leading rest element. Some oddities and challenges have emerged in such contexts, illustrated by the example highlighted in microsoft/TypeScript#47487. Although the mentioned issue has been resolved in TypeScript 5.1, it may not directly correspond to your situation. You might consider submitting a bug report or feature request to potentially address similar concerns effectively.


For the provided example, a potential strategy could involve exploring the implementation of a "reverse mapped type", whereby a generic function utilizes a homomorphic mapped type as the parameter type. By following this approach, you can infer the generic type parameter T from {[K in keyof T]: F<T[K]>}, as demonstrated below:

declare function makeHandler<T extends any[]>(
  ...a: [...{ [I in keyof T]: Assertion<T[I]> }, HandlerCb<T>]
): void;

This setup facilitates the easier inference of T, representing the tuple of return types from your Assertions. Consequently, the inference for HandlerCb<T> becomes more straightforward as well. The modified code snippet should yield the desired inference outcomes.

// Additional examples and explanations included within the original text

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 is a more effective approach for managing form data with React's useState hook?

Seeking a more efficient solution to eliminate redundancy in my code. Currently, I am utilizing useState() for managing user data, which results in repetition due to numerous fields. Below is a snippet of my current code: const [lname, setLast] = useState& ...

Tips for addressing style issues within innerText

I am trying to use PrismJS to highlight HTML code, but the inner text function doesn't recognize line breaks (\n). <pre class="language-markup background-code"><code [innerText]="getHtmlCode()""></code> I have been working wi ...

The most suitable TypeScript type for a screen being utilized again in react-navigation v5

When it comes to typing screens under react-navigation v5, I usually follow a simple pattern: // Params definition type RouteParamsList = { Screen1: { paramA: number } Screen2: undefined } // Screen1 type Props = StackScreenProps<R ...

The issue of losing context when using Papaparse with an Angular 4 function

Check out this block of code httpcsv2Array(event) { var gethttpcsv = Papa.parse('https://docs.google.com/spreadsheets/d/e/yadyada/pub?output=csv', { download: true, header: true, ...

Typescript throws an error indicating that the "this" object in Vue methods may be undefined, displaying error code TS2532

As a beginner in question writing, I apologize if my wording is not clear. The issue at hand: I am working on a Vue application with TypeScript. export default { methods: { setProgram: (program: Program)=>{ this.program = progra ...

Property of object (TS) cannot be accessed

My question relates to a piece of TypeScript code Here is the code snippet: export function load_form_actions() { $('#step_2_form').on('ajax:before', function(data) { $('#step_2_submit_btn').hide(); $(&ap ...

Having trouble getting the Typescript overload arrow function to function properly

(I am implementing strict null checks) The arrow function I have includes overloaded types: type INumberConverter = { (value: number): number; (value: null): null; }; const decimalToPercent: INumberConverter = (value: number | nul ...

Typescript: The original type cannot be indexed with a type-mapped type

I'm currently working on a class where I need to define a method that returns an object with keys based on the generic type inferred by the compiler. However, I've encountered an issue with the code snippet below. The compiler is indicating that ...

An error occurred while trying to load the configuration "next/core-web-vitals" for extension

If you're embarking on a new project using NextJs and TypeScript, chances are you may encounter the following error: Failed to load config "next/core-web-vitals" to extend from. Wondering how to resolve this issue? ...

What is the best way to verify that all elements within an object are 'false' except for one that is 'true'?

I am working with an object that has multiple boolean fields: type SomeObject = { A: boolean B: boolean C: boolean .... } Is there a simple and efficient method to determine if all other fields (except for a specified one) are set to false? We co ...

Enhance your workflow with Visual Studio Code by incorporating multiple commands

Embarking on my journey to create my first VSC extension by following this tutorial. Within the "extension.ts" file resides a simple hello world command. My ambition is to introduce another command called git_open_modified_files, however, the tutorial la ...

Steps to integrating an interface with several anonymous functions in typescript

I'm currently working on implementing the interface outlined below in typescript interface A{ (message: string, callback: CustomCallBackFunction): void; (message: string, meta: any, callback: CustomCallBackFunction): void; (message: string, ...m ...

Updating the latest version of Typescript from NPM is proving to be a challenge

Today, my goal was to update Typescript to a newer version on this machine as the current one installed is 1.0.3.0 (checked using the command tsc --v). After entering npm install -g typescript@latest, I received the following output: %APPDATA%\npm&b ...

The variable 'BlogPost' has already been declared within the block scope and cannot be redeclared

When working with Typescript and NextJS, I encountered the following Typescript errors in both my api.tsx and blogPost.tsx files: Error: Cannot redeclare block-scoped variable 'BlogPost'.ts(2451) api.tsx(3,7): 'BlogPost' was also dec ...

Issue encountered while attempting to utilize a basic redux reducer to define a boolean value, regarding a mismatch in overrides

Currently, I am working on a project to enhance my understanding of Redux and Typescript. I am still navigating through the learning curve in this area. Based on what I have learned from a book, I have established a "slice" that includes definitions for r ...

What is the best way to display the arrows on a sorted table based on the sorting order in Angular?

I need assistance with sorting a table either from largest to smallest or alphabetically. Here is the HTML code of the section I'm trying to sort: <tr> <th scope="col" [appSort]="dataList" data-order ...

Dealing with Typescript Errors in Ionic3: How to Handle "Property 'x' does not exist on value of type 'y'" Issues

I stumbled upon this particular post (and also this one) while searching for a solution to my issue. I am looking to suppress these specific errors: 'Payload' property is missing from the 'Matatu' type. 'Key' property is no ...

How to send a dynamic URL parameter to a function in Next.js TypeScript without using implicit typing

When utilizing the useRouter function with a parameter of type string, the following error is encountered: Type 'string | string[] | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type & ...

The efficiency of React Context API's setters is remarkably sluggish

I have a goal to implement a functionality where the background gradient of a page changes depending on whether the child's sublinks are expanded or collapsed. To achieve this, I am using the useContext hook. However, I've noticed that although e ...

Understanding how to efficiently map through FontAwesome icons using React TypeScript and effectively showcase them on the frontend

I am in the process of developing a versatile component that allows me to input the href, target, and rel attributes, along with specifying the FontAwesome Icon I want to utilize. My goal is to be able to pass multiple icons into this list, which will then ...