Utilizing TypeScript's type inference within a higher order function to determine the input of the returned function

I have been working on creating a versatile "pipe" function that takes a series of map functions to transform an input and then output the result of the final map function. Initially, I only implemented a basic version that accepts one map function as a parameter:

const pipe = <T, U>(map: (input: T) => U) => (initial: T): U => map(initial);

However, when I tested it with an identity function, it returned unknown:

// test is unknown
const test = pipe(i => i)(1);

In this scenario, ideally, test should be of type number.

My theory is that pipe(i => i) is interpreted as pipe(unknown => unknown), and no inference is made from the returned function. By calling pipe(unknown => unknown)(1), it's acceptable to pass a number into a function that expects unknown. However, since the function also returns unknown, that becomes the final result.

I am curious if my hypothesis is accurate and whether there are any discussions about it within the TypeScript development community.

Is there currently a solution in TypeScript that can achieve what I'm aiming for?

Answer №1

Your identity function attempts to determine the type based on the caller, while your pipe function tries to deduce the type from the callback, resulting in an unknown type.

To resolve this issue, you need to specify the type either in the pipe function or in the i=>i parameter, or make i=>i generic.

const pipe = <T, U>(map: (input: T) => U) => (initial: T): U => map(initial);

const test0 = pipe(<T, >(i: T) => i)(0) // 0
const test1 = pipe<number, number>(i => i)(0) // number
const test2 = pipe((i: number) => i)(0) // number

Answer №2

The main concern arises from the fact that the function (i) => i - the specific data type for the input (i) remains unknown.

A possible solution would involve clearly defining the input data type:

Explore Typescript playground: link description

const test = pipe((i: number) => i)(1);

To enable a sequence of pipes where the output of one serves as the input for the next, a pipeline structure must be established. This can be achieved as follows:

type PipeFunction<Input, Output> = (input: Input) => Output;

class PipeBuilder<FirstInput,LastInput,LastOutput> {
    constructor(private pipes: Array<(input: any) => any>) {}

    public static of<Input, Output>(fn: PipeFunction<Input, Output>): PipeBuilder<Input, Input, Output> {
        return new PipeBuilder([fn]);
    }

    public pipe<Output>(fn: PipeFunction<LastOutput, Output>): PipeBuilder<FirstInput, LastOutput, Output> {
        return new PipeBuilder([ ...this.pipes, fn ]);
    }

    public build(): PipeFunction<FirstInput, LastOutput> {
        return (firstInput: FirstInput): LastOutput => {
            let result = this.pipes[0](firstInput);
            for(let i = 1; i <= this.pipes.length; i++) {
                result = this.pipes[i](result);
            }
            return result as any as LastOutput;
        } 
    }
}

Subsequently, these pipes can be utilized and linked together in the following manner:

Demonstration with complete builder setup here

const pipeBuilder = PipeBuilder
    .of((num: number) => num.toString())
    .pipe((str) => parseInt(str))
    .pipe(num => new Date(2022,1,1, num))
    .pipe(date => "The date is: " +  date.toISOString());


const materializedFunction = pipeBuilder.build();
const result = materializedFunction(5);
console.log(result);

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

Attempting to utilize Pinia without a corresponding component will result in an error indicating that there are no

In my Vue.js 3 project using the ViteSse template, I encountered an issue when trying to access my Pinia store named notificationStore outside of the setup component. When running the dev command, I received an error message saying "getActivePinia called w ...

Issue with Angular2: The [routerLinkActive] directive does not update when using _router.navigate

My app includes several routerLinks that I have styled using [routerLinkActive]="['active']". Everything works perfectly when I click on one of the routerLinks to navigate. However, when I try to navigate using: this._router.navigate( [ thisUrl ...

How can a TypeScript Type be handed over as a prop to a React component?

Can you pass a TypeScript type as a property to a React Component? export type ActivitiesType = { RUN: "RUN"; WALK: "REST"; ROUNDS: "ROUNDS"; }; <MyComponent activity={ActivitiesType.RUN} /> Next, in MyComponent: const MyComponent = ({ act ...

What is the TypeScript alternative for `const x = require("somemod")();`?

When working with node.js in my TypeScript project, I'm incorporating jsreport-core. In their code, they import it using var jsreport = require('jsreport-core')(); with the trailing (). I'm interested in finding out the most effective w ...

Angular is having trouble with disabled dates on the HTML5 Datepicker

I am encountering an issue with disabling past dates in a date-picker using HTML5. When I use the date-picker without any specific conditions, the disabled dates work as expected. However, when I try to use the date-picker with conditions, it does not fun ...

The Mat table is not updating on its own

I am facing an issue in my Angular application where a component fetches a hardcoded list from a service and subscribes to an observable to update the list dynamically. The problem arises when I delete an element from the list, as it does not automaticall ...

Property of a general object

I am working with an Interface export interface ChartDataResponseI { consumption: string generation: string measure_name: string point_delivery_number: string self_coverage: string time: string } My goal is to create a generic object property ...

Unable to open modal externally without encountering an error in MaterializeCSS

I'm currently facing an issue with a standard modal that pops up at the bottom of the page. I have a function that generates multiple components on the page, each with a 'play' button. When this button is clicked, it triggers a function pass ...

Customize Material-UI Icons styles in React app

I'm working on a React.js app with Typescript and I need to remove the default visited Material Icons coloring from an anchor tag. Here's the stylesheet I tried: const useStyles = makeStyles((theme: Theme) => createStyles( myAnchor: ...

Discover the process of uploading a file using a post request in Protractor with TypeScript

Currently, I am developing a Protractor project with the TypeScript Cucumber framework. In this project, I am using the "typed-rest-client/HttpClient" package to fetch API responses. I have encountered an issue where I am unable to post an HTML file in th ...

Substitute this.bindMethod for function component

I have a class component that is structured like this: interface MyProps { addingCoord: any resetCoords: any } interface MyState { x: any y: any } class DrawerOld extends React.Component<MyProps, MyState> { width: number height: number ...

What is the best way to convert Angular form data into a POST request that the server can process?

In search of a solution to properly send data to the server in a format that it can accept. Currently, the title and descriptions are being successfully transmitted but the ratings are not coming through. It should be noted that there will be more than two ...

Ways to conceal a div when the array length is zero

I am faced with an issue regarding filtering a table of objects (Bills => Bill => Products => Product) using pipes. The pipe filtering works correctly, but even after the arrays have been filtered, the names (bill.name) are still visible when they ...

obtain a list of elements using ViewChild attribute

In Angular 8, I have created a generic form with a form array. I am trying to retrieve all elements that contain the ViewChild id. However, when I try to output the ViewChild element using console.log, it only displays one element instead of a list. How ...

What could be causing the malfunction when using TypeScript's generic T with any?

The playground demo The diff: A: function<T extends { status: number }> () {} B: function<T = any> () {} the B does not have access to T's property, while the A function only accesses T's status. Thank you ...

Is it possible for an Interface's property to be a type that contains an array?

As I dive into the Angular code, I encountered a peculiar type for a property within an Interface named 'Origin' that has left me perplexed. Here's the snippet: export interface Origin { areaNum?: number; open?: { [key: stri ...

Can you explain the process of type casting an object in TypeScript?

Looking at this example, I am pondering how to convert an Object into an interface (or a class): interface Person { firstName: string; lastName: string; } var obj={firstName:"James", lastName:"Bond"} as Person; console.log(type ...

Unexpected behavior with Angular 10 behavior subject - encountering null value after invoking .next(value) function

Can anyone help me solve the mystery of why my user value turns null after I log in? This is the login page where an API is called and the result is obtained as shown below: https://i.stack.imgur.com/kDjSy.png Here is the authentication service implemen ...

Trouble Loading TypeScript Class in Cast Situation

I've encountered an issue with my TypeScript model while using it in a cast. The model does not load properly when the application is running, preventing me from accessing any functions within it. Model export class DataIDElement extends HTMLElement ...

Is it possible to enable full screen window functionality in Angular 2 by simply clicking a button? Let's find out

After successfully creating the user login page, I am facing an issue. When the submit button is clicked, the page should navigate to a specific component (test.component.ts and test.component.html). My goal now is to make that window go into full screen m ...