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

The output type of a function given an input

Essentially, I have successfully rendered a return type for my combined reducers using the following code: const rootReducer = combineReducers({ notes: notesReducer, categories: categoriesReducer, flyout: flyoutReducer // more reducers }); export ...

Tips for updating components with fresh data in Next.JS without having to refresh the page

As part of my Todo-App development project, I am utilizing technologies such as Next.JS, Prisma, Typescript, and PostgreSQL. The data retrieval process involves the API folder interacting with the database through Prisma. CRUD operations on the Task table ...

What is the best way to specify types for a collection of objects that all inherit from a common class?

I am new to typescript and may be asking a beginner question. In my scenario, I have an array containing objects that all extend the same class. Here is an example: class Body{ // implementation } class Rectangle extends Body{ // implementation } class ...

How to trigger a function in a separate component (Comp2) from the HTML of Comp1 using Angular 2

--- Component 1--------------- <div> <li><a href="#" (click)="getFactsCount()"> Instance 2 </a></li> However, the getFactsCount() function is located in another component. I am considering utilizing @output/emitter or some o ...

The utilization of a Typescript Generic for basic addition is not producing the desired results

This issue feels incredibly insignificant, but for some reason I can't seem to figure out why it's not functioning correctly. It seems like the return type should match since I am simply concatenating or adding based on whether it's a number ...

Is there a way to set up TS so that it doesn't transpile when an error occurs?

Is there a way to configure my tsconfig.json file in order to prevent transpiling if an error occurs? I have searched the documentation but couldn't find any flag or configuration for this. Does anyone know how I can achieve this? ...

Incorporate service providers into models with Ionic3/Angular4

I am seeking feedback from individuals with more experience than me to determine if my approach is correct. I am currently working on an Ionic3-Angular app that involves a CRUD functionality for "Clientes". From what I have researched, the recommended st ...

Typescript encounters issues when assigning declaration as TRUE

Currently, I'm working on a project in Angular 2 and attempting to create TypeScript definitions for it so that it can be exported as a library. I have various services set up that make HTTP requests to components, all structured similarly to the cod ...

What could be the reason for my Angular 2 app initializing twice?

Can someone help me figure out why my app is running the AppComponent code twice? I have a total of 5 files: main.ts: import { bootstrap } from '@angular/platform-browser-dynamic'; import { enableProdMode } from '@angular/core'; impor ...

What is the process for setting up custom global interfaces in TypeScript using .d.ts files?

I'm currently facing an issue in my ReactJS project using Webpack2 and TypeScript. Everything is functioning perfectly except for one thing - I've been struggling to move my self-written interfaces into separate files so they are accessible throu ...

acquire tabulations from every single document within the templates on DocuSign

When using Docusign, it is possible to retrieve tabs data for a specific document within a template by specifying the documentId. However, I have not been able to locate a method to obtain tabs data for all documents contained within a template. ...

What is the best way to add query parameters to router.push without cluttering the URL?

In my current project, I am using NextJS 13 with TypeScript but not utilizing the app router. I am facing an issue while trying to pass data over router.push to a dynamically routed page in Next.js without compromising the clarity of the URL. router.push({ ...

How can I dynamically render a component using VueJS?

Incorporating a component named CanvasComp from my components folder, I am rendering it on the template like <CanvasComp :jsoData="data"/> to send jsonData to the component. However, I am seeking a way to dynamically render this component w ...

Set the GridToolbarQuickFilter text box to have an outlined style in Material UI v5

How can I customize the appearance of the GridToolbarQuickFilter textbox, such as outlining it? Ideally, I would like to accomplish this through theme.tsx, but I am open to any suggestions. https://i.stack.imgur.com/H1Ojj.png I have experimented with var ...

I'm having trouble understanding why I can't access the properties of a class within a function that has been passed to an Angular

Currently, I have integrated HTML 5 geolocation into an Angular component: ... export class AngularComponent { ... constructor(private db: DatabaseService) {} // this function is linked to an HTML button logCoords(message, ...

TypeScript - Variable is inferred to have type 'any' in certain locations where its type cannot be accurately determined

I'm attempting to generate an MD5 hash from the content of an uploaded file. I am trying to set a global declaration to be used within functions, but I encounter an error when trying to utilize it: The error message states - Variable 'hasher&apos ...

Tips for adding a time increment of 24 hours to a date variable in Angular 6

My goal is to update a date variable called EndDate stored in localStorage by adding exactly 24 hours to it. The current value in the localStorage is Sun Jun 09 2019 20:39:44 GMT+0530 (India Standard Time). var endDate = new Date(); endDate.setDat ...

Revamp the button's visual presentation when it is in an active state

Currently, I'm facing a challenge with altering the visual appearance of a button. Specifically, I want to make it resemble an arrow protruding from it, indicating that it is the active button. The button in question is enclosed within a card componen ...

Find the object in the array that has a name that is a combination of

I am facing an issue in implementing TypeScript validation for filtering an array. I have a specific array of actions and I want to filter out internal actions from it. Despite my efforts, I am unable to properly communicate to TypeScript that the filtered ...

Using Typescript for AngularJS bindings with ng.IComponentController

Currently, I am utilizing webpack alongside Babel and Typescript Presently, the controller in question is as follows: // HelloWorldController.ts class HelloWorldController implements ng.IComponentController { constructor(private $scope: ng.IScope) { } ...