Create a function that takes in a function as an argument and generates a new function that is identical to the original function, except it has one

I want to establish a function called outerFn that takes another function (referred to as innerFn) as a parameter. The innerFn function should expect an object argument with a mandatory user parameter. The main purpose of outerFn is to return a new function (known as returnFn) that resembles the type of innerFn, but without requiring the user parameter in its argument object (while still needing all other arguments).

This setup allows me to have outerFn return a returnFn that essentially executes the innerFn automatically injecting the user (without the need for manually passing it).

For example:

type User = { user: { id: number, name: string } };
// More code examples here...

In my attempt at implementing outerFn, I encountered an error concerning the parameters passed to innerFn.

// TypeScript code showcasing the issue...

The specific error message related to the assignment between different types and constraints within the function. I am struggling to comprehend why the typings are incorrect in this scenario.

If you can provide any insights or assistance on understanding why the typing mismatch occurs, it would be greatly appreciated.

Answer №1

It seems that the error you're encountering is valid from a technical perspective. The compiler is cautious because it cannot guarantee that the argument type of innerFn will accept a broad "User" for its "user" property. An example illustrating the compiler's concern is provided below:

const innerFn = async (arg: {
    user: { id: number, name: "a" | "b" }
}) => ({ a: 1, b: 2 }[arg.user.name]).toFixed(2);

In this case, innerFn demands its argument to have the type

{ user: { id: number, name: "a" | "b" } }
, which is more specific than simply "User." Attempting to call innerFn() with an argument of type User could result in a runtime error if arg.user.name is neither "a" nor "b", leading to a TypeError due to dereferencing undefined.

However, your typings for outerFn() do accept innerFn without any issues:

const returnFn = outerFn(innerFn); // no compiler error

The inferred type Args is

{user: {id: number; name: "a" | "b"}}
, and
Omit<Args, "user"> & { user: { id: number; name: string; }; }
essentially equates to User. However, this alignment does not cater to what innerFn specifically requires. This conflict arises because:

// 'Omit<Args, "user"> & { user: { id: number; name: string; }; }' is assignable to the constraint of 
// type 'Args', but 'Args' could be instantiated with a different subtype of constraint 'ArgsWithUser'.

Consequently, executing returnFn() might lead to a runtime error without any prior warning from the compiler:

returnFn({}).catch(e => console.log(e)) // no compiler error, but:
// 💥 (intermediate value)[arg.user.name] is undefined 

This situational inconsistency exists. While quite unlikely, you may consider performing an assertion (or what you referred to as a "cast") to swiftly move forward.


If you wish to refactor and circumvent this issue effectively, you can incorporate "User" into a type by supplementing it instead of excluding it:

type InnerFn<A, R> = (args: A & User) => Promise<R>
type ReturnFn<A, R> = (args: A) => Promise<R>

const outerFn = <A, R>(innerFn: InnerFn<A, R>): ReturnFn<A, R> => {
    const user: User['user'] = {
        id: 1,
        name: 'Something',
    };
    return async (argsWithoutUser) => innerFn({ ...argsWithoutUser, user });
};

This solution entails no compilation errors and functions correctly with the examples presented. Its applicability to your specific scenario remains uncertain, but the compiler satisfaction stands nevertheless.

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

What is the best way to toggle a card within a collection of cards using Angular?

Wishing you a wonderful day! I simply desire that when I click on a card, only that specific card flips over. But unfortunately, all the cards flip when I click on just one. HTML TypeScript ...

Issue with triggering (keyup.enter) in Angular 8 for readonly HTML input elements

My goal is to execute a function when the user presses Enter. By setting this input as readonly, my intention is to prevent the user from changing the value once it has been entered. The value will be populated from a popup triggered by the click attribut ...

Utilizing Typescript, create a customized dropdown with react-bootstrap for a tailored user

I've been working on incorporating a custom toggle drop-down feature based on the example provided on the react-bootstrap page, using Typescript and react functional components. Below is the code snippet for my component: import React from &apos ...

Receiving a conduit from the fuel supplier with only limited information on hand

I am designing a service that will utilize pipes as templates. In order to accomplish this, I require access to the registered pipes. The final code structure should resemble the following: @Injectable() class MyService { constructor(private injector ...

Resolve the clash between Jest and Cypress within a React application developed using TypeScript

Encountering a conflict in the React app after installing Cypress with TypeScript. Despite trying to resolve it using GitHub solutions, the issue persists. I am sharing all configuration files in hopes that someone can identify the problem. cypress/tsconfi ...

What is the best way to retain all checkbox selections from a form upon submission?

I have a batch of checkboxes that correspond to the profiles I intend to store in the database. HTML: <tr *ngFor="let profile of profiles | async"> <input type='checkbox' name="profiles" value='{{profile.id}}' ng-model=&apo ...

Error in TypeScript React: "Could not locate module: Unable to locate 'styled-components'"

Even though I have installed the @types/styled-components package and compiled my Typescript React app, I am consistently encountering this error: Module not found: Can't resolve 'styled-components' I have double-checked that 'style ...

Iterating over an object and inserting values into a JavaScript object using the ascending count as the identifier

Illustration: { Are you a coffee drinker?: yes, Do you like to exercise regularly?: no, How often do you eat out at restaurants?: 3 times a week, What is your favorite type of cuisine?: Italian } Results: {yes: 1, no: 1, 3 time ...

Implementing reCaptcha on React Native: A Step-by-Step Guide

Currently, I am in the process of integrating a reCaptcha validator into a login screen for a react-native application that needs to function seamlessly on both web and mobile platforms. Despite being relatively new to programming and lacking experience w ...

Exploring Typescript keyof in Storybook's User Interface customizations

Currently, I am working on developing components for integration with Storybook, but I am encountering an issue related to Typescript inferred types. While striving for code reusability, I prefer not to specify the options for a control within the story i ...

How can we include additional types for external npm packages in a React TypeScript project?

Recently, I encountered an issue while using the react-microsoft-login package from npm. I included a button in the children property and received a typescript error stating that "property 'children' does not exist on type 'intrinsicattribut ...

Discovering a method to detect clicks outside of a React functional component

Looking to identify when a click occurs outside of a React functional component. After stumbling upon an article, I followed the provided code but unfortunately, it didn't work as expected. Despite identifying the issue, I am still searching for a so ...

The function 'appendChild' is not recognized on the type 'unknown'.ts(2339)

I'm encountering an issue while trying to integrate the Utterances component into my articles. Upon attempting to build the site, I receive the following error message: "Property 'appendChild' does not exist on type 'unknown' ...

Error: Cannot access Angular 5 Title service at this time

When attempting to change the page title using BrowserModule, I encountered an issue. I added the BrowserModule and Title in the application module as shown here: https://angular.io/guide/set-document-title However, in a child module where I tried to add ...

Angular 2: The linting error shows up as "Anticipated operands need to be of the same type or any"

So, I have this shared service file where a variable is defined like so: export class SharedService { activeModal: String; } Then, in my component file, I import the service and define it as follows: constructor(public sharedService: SharedService) ...

What is the most effective way to retrieve the value of a child component in Angular 2 and pass it to the parent component?

I am working on a project with a child component (calendar) and a parent component (form). I need to select a value in the calendar and then access that value in the form component. What is the best way to achieve this? Child Component.ts: import { ...

Conceal mat-table column when form field is empty

As a newcomer to the world of programming, I am currently tackling a table that includes form fields for filtering purposes. My goal is to dynamically hide or show table columns based on whether a form field has a value or not. In my table.component.ts ...

Encountering a Typescript issue with mongoose

Working with node.js and various email addresses, I encountered a compile error: TS2345: Argument of type '(error: any, document: any) => void' is not assignable to parameter of type '(err: any) => void'. This error occurs at the l ...

Incorporate matter-js into your TypeScript project

Upon discovering this file: https://www.npmjs.com/package/@types/matter-js I ran the following line of code: npm install --save @types/matter-js When I tried to use it in the main ts file, an error message appeared: 'Matter' refers to a U ...

Embed the getServerSideProps function within a helper method

I have multiple pages that require protection using firebase admin methods: const getServerSideProps = async (ctx: GetServerSidePropsContext) => { try { const cookies = nookies.get(ctx); const token = await firebaseAdmin.auth().verifyIdToken(c ...