What is the method for utilizing Tuple elements as keys in a Mapped Type or template literal within typescript?

Is there a specific way to correctly type the following function in TypeScript?

Assuming we have a function createMap() that requires:

  • a prefix (e.g. foo)
  • and a tuple of suffixes (e.g. ['a', 'b', 'c'])

If we call

createMap('foo', ['a', 'b', 'c'])
, we expect to get the mapped type below:

  {
    a: 'foo.a',
    b: 'foo.b',
    c: 'foo.c',
  }

The actual function logic is pretty straightforward, but defining the return type may not be as easy:

const createMap = <P extends string, S extends string[]>(prefix: P, suffixes: [...S]) => {
  return suffixes.reduce((map, suffix) => ({
    ...map,
    [suffix]: `${prefix}.${suffix}`,
  }), {});
}

I am aware that this is incorrect, but one might assume it should look something like { [K in S]: ${P}.${K in S} }.

Answer №1

In order to determine the return type of the function, a mapped type can be utilized. The process involves iterating over the elements within S and calculating the union S[number]. Each individual element K is then able to combine the prefix P with a template literal type.

const createMap = <
  P extends string, 
  S extends string[]
>(prefix: P, suffixes: [...S]) => {
  return suffixes.reduce((map, suffix) => ({
    ...map,
    [suffix]: `${prefix}.${suffix}`,
  }), {}) as { [K in S[number]]: `${P}.${K}` }
}

const result = createMap('foo', ['a', 'b', 'c'])
//    ^? const result: { a: "foo.a"; b: "foo.b"; c: "foo.c"; }

Playground

Answer №2

To successfully attain this, ensure that the list is declared as const

Afterwards, follow these steps:

type GenerateMap = <S extends string, A extends ReadonlyArray<string>>(s: S, a: A) => {
  [K in (A extends ReadonlyArray<infer U> ? U : never)]: `${S}.${K}`
};

const generateMap: GenerateMap = (s, a) => {
  return Object.fromEntries(a.map(key => [key, `${s}.${key}`])) as any
}

const items = ['one', 'two', 'three'] as const

const result = generateMap('bar', items)

An illustrative example can be viewed here

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

What are the steps to lift non-React statics using TypeScript and styled-components?

In my code, I have defined three static properties (Header, Body, and Footer) for a Dialog component. However, when I wrap the Dialog component in styled-components, TypeScript throws an error. The error message states: Property 'Header' does no ...

Utilizing ES6 Map type in TypeScript for Angular 2 Response Data Transfer Object Definition

Is it possible to utilize the es6 Map type in an HTTP Response DTO? Let's consider an Angular 2 request: public loadFoos(): Observable<FoosWrapper> { return this.http.get("/api/foo") .map(res => res.json()); } Now, take a loo ...

Encountered an issue during the transition from Angular 7 to Angular 9

After following the advice in the second response of this discussion, I successfully upgraded to Angular 9. However, I am now encountering an issue in the browser console when running my project. Package.json "dependencies": { "@angular-devkit/build- ...

Validating React components with TypeScript using an array structure where the field name serves as the key

Trying to implement form validation with React. I have a main Controller that contains the model and manages the validation process. The model is passed down to child controllers along with the validation errors. I am looking for a way to create an array ...

Azure function indicates a successful status despite receiving a result code of 500

I have an Azure function containing some logic with a basic try-catch structure (code shortened). try { // perform logic here that may fail } catch (ex) { context.log(`Logging exception details: ${ex.message}`); context.res ...

What is causing the subscriber to receive the error message "Cannot access 'variable' before initialization" while referencing itself?

Within my Angular 8 project, I have a component that is dependent on a service for data loading. It waits for a notification from the service signaling that it has finished loading in the following manner: constructor(public contentService: ContractServic ...

Retrieving specific properties from a JSON object and logging them

I am attempting to access JSON Object properties directly and log them using the following function : loadProcesses(filter?){ this._postService.getAllProcess(filter) .subscribe( res=> { this.processListe = res; // console.log(this.p ...

The Microsoft.Azure.WebJobs.Script encountered an issue while attempting to cast an object of type 'System.String' to type 'Microsoft.AspNetCore.Http.HttpRequest' during the return process

I recently encountered an issue with my Azure Function written in JS that is triggered by the Service Bus and generates files to Blob Storage. When attempting to return an HTTP result, I received the following error message: System.Private.CoreLib: Except ...

There was an error encountered: Uncaught TypeError - Unable to access the 'append' property of null in a Typescript script

I encountered the following error: Uncaught TypeError: Cannot read property 'append' of null in typescript export class UserForm { constructor(public parent: Element) {} template(): string { return ` <div> < ...

Creating a dropdown menu in Bootstrap 5 without using any of the Bootstrap

In my Angular application, I have a header with icons and pictures that I would like to use as dropdown menus. The code snippet for this functionality is shown below: <li class="nav-item dropdown"> <a class="nav-li ...

Troubleshooting connectivity problems: SocketIO integration with microservices on a Kubernetes platform

I have organized my system using microservices architecture, with separate services for client interactions, orders, payments, and more. Each of these services runs on its own express server. Now, I am looking to integrate real-time feedback functionality ...

RxJS BehaviorSubject allows you to retrieve the current value or obtain a new one depending on a specific condition

I am managing a subject that consumers subscribe to: private request$: Subject<Service> = new BehaviorSubject(null); Upon initialization, my components utilize this function: public service(id: number): Observable<Service> { return this. ...

The stacked bar chart in Apex is not displaying correctly on the x-axis

Currently, I am utilizing the Apex stacked bar chart within my Angular 16 project. In this scenario, there are 4 categories on the x-axis, but unfortunately, the bars are not aligning correctly with the x-axis labels. The data retrieved from my API is as ...

Navigate to a different page using the A-g Grid router when a row is

Having trouble making the router link interact with Ag grid. When I use the router link ="url", it always takes me to a different page every time I click on anything in the grid. What I really want is for clicking on an individual row to redirect me to an ...

Is there a way to verify the availability of an authenticated resource without triggering a pop-up for credentials in the browser?

I am facing the challenge of fetching data from a web service located on a different server without knowing if the user has an active session on that server. If the user does have a session, I want to retrieve the data automatically. However, if they do no ...

Definition in Typescript: The term "value is" refers to a function that takes in any number of arguments of

export function isFunction(value: any): value is (...args: any[]) => any { return typeof value === 'function'; } What is the reason behind using value is (...args: any[]) => any instead of boolean ? ...

Extract the initial sentence or the opening 50 words from a data object in Typescript/JavaScript

Is there a way to extract only the initial line or first 50 words from the data retrieved by the API and store it in a variable? In the HTML File: <td *ngIf="customizedColumns?.details_of_non_conformity?.value"> <span [ngCl ...

Creating an auth guard in Angular Fire v7 using the latest API (not backwards compatible)

I encountered an issue Error: Unable to handle unknown Observable type when attempting to utilize v7 Angular Fire with the latest API. Specifically "@angular/fire": "^7.4.1" which corresponds to angular 14, firebase 9. Please not ...

What is the best way to create a calendar that displays every day in a single row?

Is it possible to create a calendar with all days in one row? I've been searching for a solution to this problem without any luck. It's surprising that I haven't found a clear answer or explanation on how to achieve this. I'm sure man ...

Understanding and parsing JSON with object pointers

Is it possible to deserialize a JSON in typescript that contains references to objects already existing within it? For instance, consider a scenario where there is a grandparent "Papa" connected to two parents "Dad" and "Mom", who have two children togeth ...