A Typescript generic that creates a set of builder function interfaces

Consider a Typescript interface:

interface Product {
  url: URL;
  available: boolean;
  price: number;
}

We need to create a generic type that can produce a builder type based on any given interface:

interface ProductSteps {
  url: (data: unknown) => URL;
  available: (data: unknown) => boolean;
  price: (data: unknown) => number;
}

One approach is to utilize the Record utility type to generate the Builder:

type Steps<T> = Record<keyof T, (data: unknown) => T[keyof T]>
type ProductSteps = Steps<Product>;

Although this method works, it allows any of the value types of Product as return types:

type ProductSteps {
  url: (data: unknown) => URL | boolean | number;
  available: (data: unknown) => URL | boolean | number;
  price: (data: unknown) => URL | boolean | number;
}

Any suggestions on how to constrain the return type of the builder functions to their corresponding type in Product?

Answer №1

To construct a mapped type, we need to define two generic values: an ObjectType such as Product, and a DataType which represents the data we are mapping. Each key of the object type ([P in keyof ObjectType]) corresponds to a function that takes the data and maps it to the value for that key in the object (

(data: DataType) => ObjectType[P]
).

type Steps<ObjectType, DataType> = {
  [P in keyof ObjectType]: (data: DataType) => ObjectType[P]
};

When we use this with a Product and a custom SomeDataInterface like so:

type Test = Steps<Product, SomeDataInterface>;

the result is:

type Test = {
    url: (data: SomeDataInterface) => URL;
    available: (data: SomeDataInterface) => boolean;
    price: (data: SomeDataInterface) => number;
}

Check out the Typescript Playground Link

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 dynamically generate multiple Reactive Forms from an array of names using ngFor in Angular?

I am in the process of developing an ID lookup form using Angular. My goal is to generate multiple formGroups within the same HTML file based on an array of values I have, all while keeping my code DRY (Don't Repeat Yourself). Each formGroup will be l ...

Exclude specific fields when updating a document in Firebase using the update()

Currently, I am storing a class in Firebase by using the update() function. Is there a way to stop specific fields (identified by name) of the object from being saved to the Firebase database? It's similar to how we use the transient keyword in Java ...

Incorporating Angular 11, Typescript, Node.js, and MySQL into the project, a feature is implemented where a button is displayed in the home component based on the Boolean value of 'mysql' only if

I am currently working on adding a new feature to my application that involves checking for specific domain email addresses during the registration process. Based on the email domain, I want to display a different button on the 'home' page for th ...

Angular is unable to start the variable_INITIALIZation process

I've created a method called get that returns data of type ProductModel. getProduct(id:number): Observable<ProductModel[]> { const url = `${'api/product/getProductById/'}/${id}`; return this.http.get<ProductModel[]>(u ...

What is the best way to create a props interface that includes state and setState values that are being

As I dive deeper into TypeScript, a hurdle has appeared in my app. Upon introducing React.FunctionComponent to my components, an issue arose with my Props interface. The error message reads: Type '({ value, setValue, }: Props) => JSX.Element' ...

How can I retrieve the row index in an Angular Mat-Table that has expandable content?

Having a mat-table with expandable content on a page, I am seeking a solution to record the row number of the table when clicked. While I successfully achieved this with a regular table in the HTML file using: <tr mat-row *matRowDef="let row; columns: ...

What is the best way to iterate through an array and dynamically output the values?

I am facing an issue with a function that retrieves values from an array, and I wish to dynamically return these values. const AvailableUserRoles = [ { label: 'Administrator', value: 1 }, { label: 'Count', value: ...

Retrieving display format or formatted value from an object with Moment.js

I am currently working on a project using Angular and Material2. Within this project, I have created a moment object in the following way: myDate = moment.utc(new Date()).format("YYYY-MM-DD HH:mm:ss"); This object is then passed as an argument to ano ...

Implementing debounce in Subject within rxjs/Angular2

I am currently building an events service, and here is the code snippet I am using: import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; export int ...

What is the correct version compatibility matrix for Expo, NPM, Node, React Native, and TypeScript?

Currently, I am in the process of setting up React Native with TypeScript. Here are the steps I followed: npx react-native init MyApp --template react-native-template-typescript I made sure to install TypeScript as well: npm install -g typescript ' ...

Error encountered when attempting to retrieve token from firebase for messaging

I am currently working on implementing web push notifications using Firebase. Unfortunately, when attempting to access messaging.getToken(), I encounter an error stating "messaging is undefined." Below is the code snippet I am utilizing: private messaging ...

NextJS Typescript Player

Encountering an issue during the build process, specifically with the error in audioRef.current.play(). The error message indicates that there is no play function available. I attempted to use an interface but it seems to not accept boolean values. Could ...

The expiration of the Gitlab CI/CD cache leads to the failure of the build process

I have an AWS CDK application in TypeScript and a simple GitLab CI/CD pipeline with 2 stages for deployment: image: node:latest stages: - dependencies - deploy dependencies: stage: dependencies only: refs: - master changes: - ...

Creating a Utils class in Vue.js with seamless access to Vuex through this.$store

I have a situation where I need to retrieve state from the Vuex store using this.$store. After some research, I discovered that creating a custom plugin with an installed instance method might be the solution. Here is my plugin implementation: index.ts i ...

React error: The module "react-router-dom" does not have a member named "useNavigate" available for export

I'm attempting to include useNavigate for use as outlined in the top answer here: react button onClick redirect page import { useNavigate } from "react-router-dom"; However, I am encountering this error: export 'useNavigate' (impo ...

When trying to upload a file with ng-upload in Angular, the error 'TypeError: Cannot read properties of undefined (reading 'memes')' is encountered

Struggling with an issue for quite some time now. Attempting to upload an image using ng-upload in angular, successfully saving the file in the database, but encountering a 'Cannot read properties of undefined' error once the upload queue is comp ...

Disable multiple buttons at once by clicking on them

What is the best way to disable all buttons in a menu when one of them is clicked? Here is my code: <div class="header-menu"> <button type="button"> <i class="fa fa-search" matTooltip="Filter"& ...

Tips for handling user click events in Angular 2?

In Angular2, I am facing an issue with two components. When a user clicks a button in component1, a method is triggered that stores data in the shared service to a variable. However, component2's ngOnInit() method initializes this variable to undefine ...

Ways to transfer information among Angular's services and components?

Exploring the Real-Time Binding of Data Between Services and Components. Consider the scenario where isAuthenticated is a public variable within an Authentication service affecting a component's view. How can one subscribe to the changes in the isAut ...

When submitting in an Angular mat-dialog, the page should refresh without closing the dialog

I recently started working with Angular and had to retrieve data from the database to populate a user grid. I successfully completed that task and then moved on to using MatDialog for creating new users. After fixing the creation services and linking them ...