The return type of TypeScript functions is not being properly documented

Can you help me understand why the result object is showing as type

{foo: unknown, bar: unknown, baz: unknown}
, when I believe it should actually be of type
{foo: number, bar: boolean, baz: string}

export function apply<A, B extends {[P in keyof A]: B[P]}>(
  functions: {[P in keyof A]: (a: A[P]) => B[P]},
  data: {[P in keyof A]: A[P]},
): {[P in keyof A]: B[P]} {
  const result = {} as {[P in keyof A]: B[P]}
  const keys = Object.keys(functions) as (keyof A)[]
  for(const key of keys)
    result[key] = functions[key](data[key])
  return result
}

const functions = {
  foo: (a: string) => a.length,
  bar: (a: number) => a === 42,
  baz: (a: boolean) => a ? 'true' : 'false'
}
const data = {foo: 'foo', bar: 42, baz: true}
const result = apply(functions, data)

Answer №1

Let's start by analyzing the issues with the current approach, specifically the types assigned to the two arguments.

functions: {[P in keyof A]: (a: A[P]) => B[P]},
data: {[P in keyof A]: A[P]}

It seems like you intend for the type A[P] to represent the value types of the object A. However, since there are no constraints on the type A, the values are inferred as unknown due to lack of specificity.

You can manually specify generic parameters when calling the apply function, like this:

type A = {} // What goes here?
type B = {} // What goes here?
const result = apply<A, B>(functions, data)

The challenge lies in determining a suitable type for A in this scenario. It appears that the only valid type would be similar to what you currently have:

{foo: unknown, bar: unknown, baz: unknown}
.


Instead of utilizing a mapped type for the arguments as shown above, why not incorporate these constraints into the generic signature itself? You seem to desire the functions parameter to consist of single-argument functions. Let's enforce that requirement directly in the generic A:

A extends Record<string, (a: any) => any>

As for B, representing the data type, it should align with the argument type of each corresponding function in

A</code. We can establish this constraint within the generic signature as well:</p>
<pre><code>B extends {[P in keyof A]: Parameters<A[P]>[0]}

Lastly, for the return type, which is another object mirroring the return types of A's functions:

{[P in keyof A]: ReturnType<A[P]>

Combining all these aspects:

function apply<A extends Record<string, (a: any) => any>, B extends {[P in keyof A]: Parameters<A[P]>[0]}>(
    functions: A,
    data: B
): {[P in keyof A]: ReturnType<A[P]> {
    const result = {} as {[P in keyof A]: B[P]}
    const keys = Object.keys(functions) as (keyof A)[]
    for(const key of keys)
        result[key] = functions[key](data[key])
    return result
}

const functions = {
    foo: (a: string) => a.length,
    bar: (a: number) => a === 42,
    baz: (a: boolean) => a ? 'true' : 'false'
}
const data = {foo: 'foo', bar: 42, baz: true}

const result = apply(functions, data)
// The type of `result` is inferred as:
// {
//    foo: number;
//    bar: boolean;
//    baz: "true" | "false";
// }

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

How can I display the top 5 data results after subscribing in Nativescript?

Utilizing this function allows me to retrieve all my data from the web service. public data: Data[]; getall() { this.ws.getalldata().subscribe( data=> { this.data= data; } ); } Here is a ...

Conceal certain components when a user is authenticated

Below is the content of my app.component.html: <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class='container'> <ul class="nav navbar-nav"> <li class='nav-item'> <a clas ...

Styling with CSS in Angular 2+ can be quite challenging

Hey there, I'm new to Angular 4 and running into some troubles with styling my application. I tried adding a background image to the body, which worked fine, and then added a component to display content, also looking good. Now, when I added a second ...

Encountering a 404 error while attempting to test a contact form on a Next.js website using a local server

Trying to test a contact form in Next.js where the data is logged but not sent to the API due to an error. "POST http://localhost:3000/app/(pages)/api/contact/route.tsx 404 (Not Found)" Troubleshooting to identify the issue. [directory setup] ...

Angular2-starter configuration setup with environment-based variables (such as .env or .conf) for testing and production settings

Frameworks like PHP Laravel often include files for local configuration, separate from dev, test, and production environments. How can a configuration file be provided for an angular-starter project that contains all local environment variable values (su ...

Transform the object type into Angular's Type<T>

After working with a list of components, an AnyComponent type, and a function to locate a specific component, I encountered an issue: const components = [Comp1, Comp2, Comp3 ...]; type AnyComponent = typeof components[number]; findComponent(id: string): ...

How to make text dynamically shrink with TailwindCSS class 'flex-shrink-0'

I've designed an 'Album' (React) component to showcase album artwork, name, and release date in a card-like format. This component consists of two divs - one for the photo and the other for text. Each artist's discography displays multi ...

React - retrieving the previous page's path after clicking the browser's "back" button

Imagine I'm on Page X(/path-x) and then navigate to page Y(/path-y). Later, when I click the "back" button in the browser. So my question is, how do I retrieve the value of /path-y in PageX.tsx? Note: I am utilizing react-router-dom ...

Next.js components do not alter the attributes of the div element

I am encountering a problem with nextjs/reactjs. I have two tsx files: index.tsx and customAlert.tsx. The issue that I am facing is that the alert does not change color even though the CSS classes are being added to the alert HTML element. Tailwind is my c ...

Higher Order Function with Generics

I am looking to create a special function that can generate a constructor function for one of my existing React components. The result will be a customized class extension of the component passed into it. In simple terms: The output of my higher-order fu ...

Creating reusable functions in VueJS that can be accessed globally by all child components

Looking for assistance in setting up a universal function that can be accessed across all my Vue files. For example, when using this code snippet in a Vue file: @click="ModalShow.show('my-create')" I have defined the following constan ...

TS - decorator relies on another irrespective of their position within the class

Is it possible to consistently run function decorator @A before @B, regardless of their position within the class? class Example { @A() public method1(): void { ... } @B() public method2(): void { ... } @A() public method3(): void { ... } } In the sc ...

How to use RxJs BehaviorSubject in an Angular Interceptor to receive incoming data

Being a newcomer to rxjs, I grasp most operators except for the specific use case involving BehaviorSubject, filter, and take. I am working on renewing an oauth access and refresh token pair within an Angular interceptor. While reviewing various codes fro ...

Stop allowing the transmission of unfamiliar string constants, but still permit the transmission of adaptable strings

Consider the TypeScript code snippet below: const namesList = { john: 25, emma: 30, jacob: 35, } type NameType = keyof typeof namesList function getPersonAge< Name extends string, Result = Name extends NameType ? number ...

Exploring the Worldwide Influence of TypeScript, React, and Material-UI

I am currently following an official tutorial on creating a global theme for my app. In my root component, I am setting up the global theme like this: const themeInstance = { backgroundColor: 'cadetblue' } render ( <ThemeProvider theme ...

Error in VueJS/Typescript: Module 'my-module' or its type declarations are not found

Hey fellow developers! I'm currently working on a Vue2 setup with Nuxt and Typescript. I'm facing an issue while trying to install the awesome vue-slick-carousel module via yarn. When attempting to import the module in my component, Typescript th ...

Having trouble getting a local npm installation to work from a specific file path?

After following the instructions from this helpful link to install an npm package through a file path, I encountered an error when attempting to use it: Cannot find module '<module_name>' or its corresponding type declaration Are there an ...

Encountering an undefined property error when trying to access 'userService' while implementing an async validator in Angular 12

For the past few days, I've been struggling to implement async validation with no success from various tutorials and solutions! Service code- getUserIdToCheckDuplicate(userId:any):Observable<any>{ const url = ``; //url goes here return ...

Suggestions for importing by Typescript/VS Code

Imagine you have a file called a.ts that contains 4 named imports: export const one = 1 export const two = 2 export const three = 3 export const four = 4 Next, you have a file named b.ts and you want to import some variables from a.ts. import {} from &a ...

Encountering a TSLint interface error when adding a value to a nested array

Currently, I am transforming responses into an array of Months and Days, with each Day containing an array of numbers. The logic itself is functioning properly, however, I am encountering a tslint error specifically when attempting to push a value into the ...