In the CallableFunction.call method, the keyword "extends keyof" is transformed into "never"

In the following method, the type of the second parameter (loadingName) is determined by the key of the first parameter.

(alias) function withLoading<T, P extends keyof T>(this: T, loadingName: P, before: () => Promise<any>): Promise<void>
import withLoading

However, when invoking withLoading.call, the type of loadingName unexpectedly changes to never:

(method) CallableFunction.call<this, [loadingName: never, before: () => Promise<any>], Promise<void>>(this: (this: this, loadingName: never, before: () => Promise<any>) => Promise<...>, thisArg: this, loadingName: never, before: () => Promise<any>): Promise<...>

Answer №1

If we aim to simplify this into a minimal reproducible example, consider the scenario where you have the function func defined as follows:

declare function func<T>(this: T, key: keyof T): void;

You attempt to call it like this, but encounter an error:

func.call({ a: 123 }, "a") // error?!
// CallableFunction.call<{ a: number; }, [key: never], void>(...);

Why does this error occur?


The issue arises when trying to combine two generic functions with the expectation that the compiler will infer a relationship between them to pass on generic type parameters without explicit specification.

Although TypeScript 3.4 introduced support for some aspects of higher order type inference from generic functions, and TypeScript 3.5 extended this to include generic constructors, it falls short in cases like this due to heuristic limitations.

Had there been a stand-alone function call() without a this parameter, the desired behavior would work:

declare function call<T, A extends any[], R>(
  thisArg: T, cb: (this: T, ...args: A) => R, ...args: A): R;
call({ a: 123 }, func, "a") // okay
call({ a: 123 }, func, "b") // error

But why doesn't it work as expected with a this parameter?


The reason lies in the fact that current support for higher order function inference is heuristic and not comprehensive. The existing algorithm, while imperfect, serves performance goals, as highlighted in microsoft/TypeScript#30215.

The above algorithm is not a complete unification algorithm and it is by no means perfect.

Achieving full unification, as discussed in microsoft/TypeScript#30134, would necessitate substantial changes to TypeScript's type inference mechanism and might impact compiler performance. For now, the algorithm remains imperfect yet efficient.


While investigating, I came across microsoft/TypeScript#33139, a pull request promising improved inference with this parameters. Despite being under the lead language architect's purview, its status has remained stagnant for some time without associated bug reports or feature requests.


To address this, an immediate workaround involves manually specifying the generic type parameters:

func.call<{ a: number }, [key: keyof { a: number }], void>({ a: 123 }, "a"); // okay

Although it's not ideal, at least such manual specifications are recognized by the compiler for func.call, eliminating the need for unsafe type assertions.

In the long run, providing feedback on microsoft/TypeScript#30215 regarding the benefits of a full unification algorithm could be beneficial. Additionally, advocating for extending TypeScript 3.4's support for higher-order functions to cover this parameters through a separate feature request linked to microsoft/TypeScript#33139 might prompt consideration, though outcomes aren't guaranteed.

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

Retrieve the specific type of property from a generic data structure

I am currently working on a project where I need to determine the type of property within a given Type: type FooBarType { foo: string, bar: number } The function would be structured like this: getType<K extends keyof T>(key: K): string. The ...

When running the test, a "is not defined" ReferenceError occurs in the declared namespace (.d.ts) in ts-jest

When running typescript with ts-jest, the application functions properly in the browser but encounters a ReferenceError: R is not defined error during testing. The directory structure: |--app | |--job.ts |--api | |--R.d.ts |--tests | |--job.test.ts ...

Angular 4's OrderBy Directive for Sorting Results

I've been working on implementing a sorting pipe based on the code provided in this resource: The issue I'm facing revolves around handling undefined values within my data. The sorting pipe functions correctly when there are no undefined values ...

Exploring the retrieval of specific values through bitwise operations in Angular

Currently, I am facing a challenge in retrieving a value that I had initially saved in the database as a sum of bits. My development work is based on Angular 9 using Typescript. I have successfully managed to store the sum of bits in the database. Now, I ...

The variable 'string' has been declared, but it is never utilized or accessed

Currently delving into Typescript and facing an early error. Despite following a tutorial, I'm encountering multiple errors that I have attempted to comment out. Would greatly appreciate it if someone could shed some light on why these errors are occu ...

Generating form groups programmaticallyORDynamically

I recently utilized angular-archwizard to implement a wizard step with *ngFor However, I encountered an issue on how to create a dynamic formGroup for each step. In the code below, I managed to create a single formGroup for all steps, but my goal is to ha ...

Tips for successfully sending an interface to a generic function

Is there a way to pass an interface as a type to a generic function? I anticipate that the generic function will be expanded in the future. Perhaps the current code is not suitable for my problem? This piece of code is being duplicated across multiple fil ...

Processing a list in Angular using Observables

In my Angular12 application, I am fetching data from a Firebase Realtime DB using AngularFire. To streamline my code and ensure consistency, I have implemented a DAO service to preprocess the retrieved data (e.g., converting string dates to Date objects). ...

Tips for implementing collapsible functionality that activates only when a specific row is clicked

I need to update the functionality so that when I click on a row icon, only that specific row collapses and displays its data. Currently, when I click on any row in the table, it expands all rows to display their content. {data.map((dataRow ...

Is it necessary to conceal Angular navigation controls when the user is not authenticated?

In Angular, is there a standardized method for hiding controls when the user is not logged in? We already have the CanActivate guard which checks if a user can access a route. Would it be better to hide the route initially if the user is not logged in or l ...

Ending the connection in SignalR upon $destroy

I am currently working on a page that is utilizing SignalR, Angular, and Typescript. Upon the destruction of the current $scope (such as during a page change), I make an attempt to disconnect the client from the SignalR server: Controller.ts $scope.$on(&q ...

Ways to verify the compatibility between TypeScript type definitions in @types and the corresponding package

After dabbling with typescript in my node.js projects for a while, I've come to realize that many npm packages have separate @types packages for typescript definitions. But here's the dilemma: how can one be certain that the @types package is syn ...

What is the best way to retrieve information utilizing Http.get within my project?

I have a TypeScript file containing user data: File path: quickstart-muster/app/mock/user.mock.ts import {User} from "../user"; export const USERS:User[]=[ new User(....); ]; I have a service set up at: quickstart-muster/app/services/user.service.ts ...

Transform JSON into an Array and generate a new Array from a collection of Arrays

I'm struggling with generating a table in Angular2 from JSON data because I need to pivot the information, but my usual method doesn't seem to work for this scenario. Below is an excerpt of the JSON data I am working with: [ { "ValueDate" ...

Using Material-UI with TypeScript

Attempting to integrate TypeScript/React with Material UI has been quite the challenge for me so far. Here is my index.tsx file: declare function require(p: string): any; var injectTapEventPlugin = require("react-tap-event-plugin"); injectTapEventPlugin( ...

Create a chronological timeline based on data from a JSON object

Here is a JSON object generated by the backend: { "step1": { "approved": true, "approvalTime": "10-11-2021", "title": "title 1", "description": "description 1" ...

Executing multiple queries in a node.js transaction with Sequelize using an array

I am looking to include the updates on the clothingModel inside a transaction, with the condition that if it successfully commits, then update the reservationModel. This is the snippet of code I am attempting to refactor using sequelize.transaction tr ...

The specified target "TypeScriptClean" is not present within the project

I'm facing some issues in Visual Studio 2017 Professional. Despite not having any TypeScript code in my solution, I am encountering numerous TypeScript-related errors during the build process. The main error message that keeps popping up is: The targ ...

"Creating a Typescript array by extracting items from a different const array (as seen in the official beginner tutorial

Currently, I am working through the Angular tutorial that can be found at https://angular.io/start. After successfully completing the tutorial, I decided to practice building for production locally. However, when attempting to build, I encountered this err ...

Angular: Real-time monitoring of changes in the attribute value of a modal dialog and applying or removing a class to the element

I cannot seem to figure out a solution for the following issue: I have two sibling div elements. The second one contains a button that triggers a modal dialog with a dark overlay. However, in my case, the first div appears on top of the modal dialog due to ...