Mapping of generic types in typescript

Consider the hypothetical type T:

type T = {
  prop1: (s: S) => T1,
  prop2: (s: S) => T2,
  prop3: (s: S) => T3,
}

Now, let's imagine type W:

type W = (s: S) => {
    prop1: T1,
    prop2: T2,
    prop3: T3,
}

It may be straightforward to manually map T to W with a function,

But can we create a generic type-safe version of this in TypeScript?

function x(t: T): W {
  return funtion(s: S) {
    prop1: t.prop1(s),
    prop2: t.prop2(s)
    prop3: t.prop3(s)
  }
}

What kind of language feature is lacking to simplify this process? Perhaps something like higher-order generic types?

Answer №1

Writing a generic version of this function in TypeScript is definitely possible:

function customFunction<S, V>(inputObj: {[K in keyof V]: (param: S) => V[K]}): (param: S) => V {
  return function(param: S): V {
    const result = {} as V;
    Object.keys(inputObj).forEach((key: keyof V) => {
      result[key] = inputObj[key](param);
    })
    return result;
  }
} 

const specificFunction: (params: T) => W = customFunction; // works fine

Note that the return type V for your W function. This means that W can be seen as similar to (param: S) => V. The input to customFunction is a mapped type related to T: it shares the same keys as V, but its values are functions from S to properties of V.

The reason you can use a mapped type as input and an unmapped one as output is because TypeScript supports inference from mapped types. If not for this, a feature like the proposed "extended typeof" would be needed to generically derive W from

T</code.</p>

<p>In terms of implementation, I iterate over the keys of <code>inputObj
and apply each function inputObj[key] to the input parameter param.

The variable specificFunction represents the same as customFunction with the specific types T and

W</code you provided. This works because TypeScript recognizes the compatibility of the generic <code>customFunction
.


However, there are some caveats to consider. The compiler may struggle to infer the type of

S</code directly from <code>customFunction
. For instance, if you call the generic customFunction() with a T input only:

declare const inputObj: T;
const outputResult = customFunction(inputObj); // (param: {}) => { prop1: T1; prop2: T2; prop3: T3; }

The outputResult does not perfectly match

W</code... it accepts any input, not just an <code>S</code. To narrow down the input type, you'll need to manually specify the generic parameters:</p>

<pre><code>const outputResult = customFunction<S, {prop1: T1, prop2: T2, prop3: T3}>(inputObj);

Alternatively, you could narrow down the resulting outputResult by assertion or annotation:

const w: W = customFunction(inputObj);

Hopefully, these insights are helpful. Best of luck!

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

Obtain data based on the type of property

When examining the provided code snippet, I aim to filter properties based on their data type: interface Wrapper<T> { x: T; } interface WrapperOpt<T> { y?: T; } interface A { a1: number; a2: Wrapper<number>; a3: Wra ...

Invoking a parent method in ReactJS through two layers of components using TypeScript

I'm facing an issue while trying to call a method from a parent component that is two layers above. Whenever I attempt to do so, nothing happens or I get an error saying that the function is not defined. Here is my Child Component: class Child extends ...

Storing a 38-digit integer in MongoDB using the Java driver: step-by-step guide

Currently making the leap from Oracle to MongoDB, with data type preservation being a critical aspect of this migration (avoiding storing numbers as strings in MongoDB for optimized indexing and aggregation performance). Within the Oracle database, there i ...

Is there a way to change ngx-timeago language when the button is pressed?

I was trying to implement ngx-timeago localization. Everything seems to be working fine, but I am struggling with changing the language from German to Spanish when a button is pressed. Here's the template I am using: {{ date | timeago:live}} <div ...

Unable to simulate Paginate function in jest unit testing

Currently, I am in the process of mocking the findAll function of my service. To achieve this, I have to decide whether to mock the repository function findAndCount within myEntityRepository or the paginate function of the nestjs-typeorm-paginate node modu ...

Encountering an error with dynamic routing in Angular 4 when using dynamic components

Upon receiving routing configuration from a server and loading it before the application bootstrap, the config.json file contains the following setup: [{ "path": "dashboard", "component": "SingleComponent", "data": {...} }, { "path": "payment", ...

Exploring deep nested components and elements in Angular for a targeted specific functionality

Is it possible to apply the ng deep css class to only one specific checkbox in my component, rather than all checkboxes? I want to customize just one checkbox and leave the others unchanged. How can this be achieved? Thank you. I need the CSS modificatio ...

A guide on configuring .env variables when importing a module or setting up configurations

I need to include a .env file in my application. I have created two files for this purpose (one module and one service): config.module.ts import {Module} from '@nestjs/common'; import {ConfigService} from './config.service'; @Module ...

The Server Components render encountered a glitch

Screenshot of the errorI am encountering a strange error only in the production environment. The lack of additional information leads me to believe it may be due to security measures put in place for production. Unfortunately, I have been unable to repli ...

Pause code execution and prompt user interaction within a loop - React

I have been working on adding an "add all" button to my React app. To achieve this, I am passing a function to the onClick method of the button: for (element in elements) { await uploadfunction(element) } const uploadfunction = async (element) => ...

Angular2 authguards encountering issues when trying to run asynchronous functions

I need a way to safeguard my routes by verifying if a user is logged in from the server, but I'm facing issues with asynchronous functions not executing properly. Below is the code snippet that's causing trouble: canActivate (route: ActivatedRo ...

Verify in TypeScript whether a property of an object is a function with a specified signature

I am facing an issue with a function that retrieves a property from an object. // Utils.ts export function getProperty<T, K extends keyof T>(obj: T, key: string): T[K] { if (key in obj) { return obj[key as K]; } throw new Error(`Invalid obje ...

Transmit a sequence of keys to the web browser

I'm having difficulty in sending a Shift key command followed immediately by tilde (~). I've attempted various examples, and here's one that I'm currently working on. I am testing the following scenario - selecting a specific image, t ...

How to display a PDF in Angular 6 using a byte array retrieved from a WebAPI

Having trouble opening a PDF from byte array sent by WebAPI. This is my Service: fetchPdfDocument(): Observable<any> { return this.httpClient .get(this.configuration.serverUrl + this.configuration.getPdfDoc, { re ...

Utilizing the functionalities provided by node.js, I came across an issue and sought out a solution for the error message "TypeError: __WEBPACK_IMPORTED_MODULE_3_fs__.writeFile is not a function"

I have created a project centered around {typescript, react, electron, gaea-editor}. During an event, I utilized fs.writeFile() but encountered an error. The specific error message was: TypeError: __WEBPACK_IMPORTED_MODULE_3_fs__.writeFile is not a functi ...

Access uninitialized properties in Typescript post-compilation

I am currently in the process of creating a wrapper for socket.io. Coming from a strong object-oriented background, I aim to incorporate the idea of Models into my framework/wrapper. For those familiar with socket.io, you may know that data associated wit ...

The property is not found in the '{}' type but is necessary in the type... Typescript connect strategy

Hello, I am currently trying to establish a connection pattern for React with TypeScript. I have a reducer set up as follows: type State = { version: number, a?: string } interface ActionC { type: string payload?: number } type IAction = Action ...

Integrating concealed elements into jspdf

I am currently working on incorporating a hidden div into my jspdf file. Utilizing html2canvas for this purpose, I find it necessary to briefly make the div visible, add it to the pdf, and then hide it again. This method is not ideal as the content moment ...

I offer a unique service that creates custom toolbars with a variety of classes to choose from

menu component import { QueryParam } from "./query-param"; import { QueryRouterLink } from "./query-router-link"; export class Menu { link: string; name: string; queryParam: QueryParam[]; queryRouterLink?: QueryRouterLink; } QueryParam class e ...

Angular: Effective communication between components through routing and Observable binding ultimately results in the advancement of ngtsc(233

I designed an Angular Component named "crear-pedido" that exhibits a catalog of items (using row of products) and my aim is for the user to have the ability to click on the values in the ID column and navigate the application to a subordinate component kno ...