Function Type Mapping

I am in the process of creating a function type that is based on an existing utility type defining a mapping between keys and types:

type TypeMap = {
    a: A;
    b: B;
}

The goal is to construct a multi-signature function type where the key is used as a literal string in the first parameter:

type Result = {
    (key: "a"): A;
    (key: "b"): B;
}

Is it feasible to achieve this in TypeScript? I'm aware that function types and mapped types may not always work well together.

I can attempt the following approach, but it involves repeating the full list of keys which I'd like to avoid:

type TempFunc<K extends keyof TypeMap> = {
    (key: K): TypeMap[K];
};

type Result = TempFunc<"a"> & TempFunc<"b">;

Note: This example is simplified; my actual TypeMap comprises over 100 keys.

Answer №1

TypeScript defines a function with multiple call signatures (referred to as an overloaded function) as an intersection of these signatures. In other words:

type Result = {
    (key: "a"): A;
    (key: "b"): B;
};

is equivalent to

type Result = { (key: "a"): A; } & { (key: "b"): B; };

which is also equivalent to

type Result = ((key: "a") => A) & ((key: "b") => B);

This can be confirmed by testing the code below using any of those Result definitions:

declare const r: Result;
const a = r("a");
// const a: A
const b = r("b");
// const b: B

Therefore, if we can produce an intersection programmatically, it will fulfill your requirement.


Fortunately, this can be achieved through a conditional type inference method involving type parameters in a contravariant position. This approach uses features detailed in the answers to questions such as Transform union type to intersection type and considers it as a distributive object type as mentioned in ms/TS#47109.


It may not always be necessary to have multiple call signatures depending on the scenario. If each call signature maps input to output in a similar fashion by indexing into TypeMap, a single generic call signature could serve a comparable purpose:

type Result = <K extends keyof TypeMap>(key: K) => TypeMap[K];

This alternative method is simpler than the previous contravariant object concept and behaves similarly when tested as shown above.

If multiple distinct call signatures are not essential for your use case, utilizing generics might be a more straightforward approach.

Link to Playground for Code Testing

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

Tips for triggering useEffect just once when various dependencies are updated simultaneously

Currently, I have implemented a useEffect hook with two dependencies in the following way: useEffect(() => { ..... }, [apiData, currentMeasurements]); It's important to note that the apiData is fetched using useLazyQuery from apollo/client. Upon ...

Unlocking the Potential of Vue Class Components: Exploring Advanced Customization Options

Currently, I am working on a project using Vue 2 with Typescript. However, I am facing an issue where I cannot add options to the component. <script lang="ts"> import { Component, Vue } from "vue-property-decorator"; import HelloW ...

Creating a List programatically in material-ui can be easily achieved by following these steps

I am attempting to create a contact view using the list component from Material-UI. My code is written in typescript, but I am struggling with setting up react and material-ui correctly. Any guidance would be greatly appreciated. export interface IConta ...

Troubleshooting the problem of redirecting a website to www on IIS 10 (Windows Server 2019)

I have a React website running on port 3000. Currently, the website can be accessed with and without the www prefix, causing duplicate SEO issues. I want to ensure that the website always redirects to https://www.pess.org.ua. web.config <?xml version=& ...

Discussing recursive types A <--> B with generics in TypeScript

I'm currently working with the following TypeScript code: type DormNodePredicate = DormEdge | (() => DormNode<DormNodePredicateRecord>); interface DormNodePredicateRecord { [key: string]: DormNodePredicate; } export class DormNode<DNPR ...

The express application's GET route is causing a "Cannot GET" error to be thrown

I am managing different types of pages: the main root page (/) today's chapter page (/929 OR /929/) which eventually redirects to /929/<CHAPTER> where <CHAPTER> is a natural number between 1 to 929 individual chapter pages (/929/<CHAP ...

Tips for refreshing the appearance of a window in angular when it is resized

I have a chat feature integrated into my application. I am looking to dynamically resize an image within the chat window when the width of the window falls below a certain threshold. Is there a method available to modify the CSS style or class based on the ...

Obtain unfinished designs from resolver using GraphQL Code Generator

In order to allow resolvers to return partial data and have other resolvers complete the missing fields, I follow this convention: type UserExtra { name: String! } type User { id: ID! email: String! extra: UserExtra! } type Query { user(id: ID! ...

The module "node_modules/puppeteer/lib/types" does not contain the export "Cookie"

Currently facing an issue with puppeteer types. I am attempting to import the Cookie type, but it seems to be not functioning on versions above 6.0.0. import { Cookie } from 'puppeteer'; Here is the error message: /node_modules/puppeteer/lib/typ ...

Yup will throw an error if both a minimum value is set and the field is also marked

I am attempting to validate my schema using yup: import * as yup from "yup"; let schema = yup.object().shape({ name: yup.string().min(5) }); const x = { name: "" }; // Check validity schema .validate(x, { abortEarly: false }) . ...

Utilizing Protractor, TypeScript, and Jasmine for Automated Testing

Just landed a new job at a company that uses protractor, jasmine, and Type Script for automation testing. While I have experience with selenium and Java, I'm unfamiliar with protractor. Can someone guide me on how to start protractor testing? Is there ...

The shape-matching subset functionality in Typescript is experiencing issues

One of the key principles of TypeScript is that type checking focuses on the structure of values, a concept known as duck typing or structural typing. This means that only a subset of an object's fields needs to match for it to be considered compatibl ...

The communication between Angular and Unity using SignalR for messaging is not functioning properly, as I am unable to

Trying to establish a connection between Angular and Unity has been challenging for me. I can't seem to get them to communicate with each other. My goal is to have Angular "announce" when someone enters a room, and have Unity "greet" the user enterin ...

Unknown error occurred in Eventstore: Unable to identify the BadRequest issue

I'm encountering an error while using Eventstore, specifically: Could not recognize BadRequest; The error message is originating from: game process tick failed UnknownError: Could not recognize BadRequest at unpackToCommandError (\node_modul ...

Next.js experiencing hydration error due to dynamic component

Having an issue with my RandomShape component, where it should display a random SVG shape each time the page is reloaded. However, I am encountering a hydration error on the client side. import React from "react"; import shapes, { getRandomShape ...

Transferring functionality from a child component to a parent component

I have a Base Component called ListComponent and a ParentComponent named Businesses2ListComponent. The concept is to have multiple types of Lists with tables that all stem from the ListComponent. This requires passing the correct service accordingly. In t ...

The type 'HttpEvent<MovieResponse>' does not contain a property named 'results'. This is causing a TypeScript Error

I'm currently integrating the TMDB trending movies endpoint into my Angular 18 application and storing the data in a variable. Here is a snippet of the code: private trendingMovies$ = this.http.get<MovieResponse>(${this.apiUrl}trending/movie/da ...

The error message "Type 'Dispatch<SetStateAction<undefined>>' cannot be assigned to type 'Dispatch<SetStateAction<MyType | undefined>>'" appears in the code

I'm encountering challenges while creating a wrapper for useState() due to an unfamiliar error: Type 'Dispatch<SetStateAction>' cannot be assigned to type 'Dispatch<SetStateAction<VerifiedPurchase | undefined>>' ...

The functionality of TypeScript's instanceof operator may fail when the method argument is not a simple object

There seems to be an issue with a method that is being called from two different places but returns false for both argument types. Despite checking for the correct types, the problem persists and I am unsure why. Although I have read a similar question on ...

Using a for-loop in Typescript to iterate over objects in an array

Consider an Array structured as follows: let bodyDataAnswer = { 'answers':[{ 'question_id':this.verifyCustomer.questions[0].id, 'int_result':this.verifyCustomer.questions[0].answer_template.answers["0"].int_result, ...