Navigating through keys within a mapped Type in Typescript

Are there alternative methods for iterating through object keys, transforming values, and ensuring the resulting type maintains the same keys as the input?

const env = {
  KEY_1: "VALUE_1",
  KEY_2: "ANOTHER_VALUE_2"
};

function mapValuesToLength<TEnv extends Record<string, string>>(
  env: TEnv
): Record<keyof TEnv, number> {
  const result: Partial<Record<keyof TEnv, number>> = {};

  for (const envKey in env) {
    result[envKey] = env[envKey].length;
  }

  return result as Record<keyof TEnv, number>;
}

// expecting result = {KEY_1: 7, KEY_2: 15}
const result = mapValuesToLength(env);

// expecting type resultType = { KEY_1: number; KEY_2: number; }
type resultType = typeof result

Answer №1

Consider trying out this alternative method (condensed into a single line):

const env = {
    KEY_1: "VALUE_1",
    KEY_2: "ANOTHER_VALUE_2"
};

type InputType = Record<string, string>;
type OutputType<T> = Record<keyof T, number>;

function mapValuesToLength<TEnv extends InputType>(env: TEnv): OutputType<TEnv> {
    return Object.entries(env).reduce((acc, [key, value]) => ({ ...acc, [key]: value.length }), {} as OutputType<TEnv>);
}

const result = mapValuesToLength(env);
console.log(result);

Key Steps to Follow:

  1. Object.entries(): Produces an array containing an object's own enumerable property [key, value] pairs.
  2. Array.prototype.reduce(): Applies a function against an accumulator and each element of the array.
    1. ({ ...acc, [key]: value.length })
      : Appends the current key-value pair with the length of its value to the existing accumulator.
    2. {} as OutputType<TEnv>: Initializes the accumulator as an empty object with the correct output type.

Visit Typescript Playground for more insight

Answer №2

Your approach to converting one object to another using imperative programming is commendable. The logic implemented with the for loop is easy to comprehend and maintain.

While the functional approach with array.reduce() is an alternative, I prefer efficiency over complexity. The direct use of a for loop is more straightforward and performs better in terms of speed, considering unnecessary computation impacts performance.

In terms of enhancing your code with types, here’s a modified version:

const env = {
  KEY_1: "VALUE_1",
  KEY_2: "ANOTHER_VALUE_2",
};

// Defining types separately for clarity
type InputString<InputType> = Record<keyof InputType, string>;
type OutputNumber<InputType> = Record<keyof InputType, number>;

function mapValuesToLength<TEnv extends InputString<TEnv>>(env: TEnv) {

  const result = {} as OutputNumber<TEnv>; 

  for (let envKey in env) {
    result[envKey] = env[envKey].length;
  }

  return result;
}

const result = mapValuesToLength(env);

type resultType = typeof result;

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

Server-side props become inaccessible on the client side due to middleware usage

I'm attempting to implement a redirect on each page based on a specific condition using Next.js middleware. Strange enough, when the matcher in middleware.ts matches a page, all props retrieved from getServerSideProps for that page end up being undef ...

Customizing a generic method in typescript

I am currently working on developing a base class called AbstractQuery, which will serve as a parent class to other classes that inherit from it. The goal is to override certain methods within the child classes. class AbstractQuery { public before< ...

Enhance the efficiency of writing the *.d.ts file

I have recently started diving into TypeScript with React and encountered a new concept called a .d.ts file. I am wondering if there is an established best practice for writing this file or if it's more of a developer preference. Can someone verify if ...

Tips for resolving this unhandled error in React TypeScript

After creating a program in React TypeScript, I encountered an uncaught error. Despite running and debugging tests and conducting extensive research on Google, I have been unable to resolve this issue on my own. Therefore, I am reaching out for assistance ...

Tips for isolating data on the current page:

Currently, I am using the igx-grid component. When retrieving all data in one call and filtering while on the 3rd page, it seems to search through the entire dataset and then automatically goes back to "Page 1". Is there a way to filter data only within th ...

Switch between classes when hovering over / exiting ngFor elements

Displayed below is an element created using ngFor <span *ngFor="let picture of pictures; let i = index"> <a target="_blank" href="{{picture.image}}" class="thumbnail-display image-overlay"> <span class="overlay-icon hide"> ...

Unable to transfer information from the Parent component to the Child component

Can you help me solve this strange issue? I am experiencing a problem where I am passing data from a parent component to a child component using a service method that returns data as Observable<DemoModel>. The issue is that when the child component ...

An angular component that is functioning properly when connected to a live server, however, it is experiencing issues when trying to run `

I tried integrating versitka into my Angular component by placing the version HTML file and all necessary assets in the appropriate directories. However, when I run ng serve, only the HTML file seems to be working, while the CSS and images fail to load. I ...

JavaScript's async function has the capability to halt execution on its own accord

Presented here is a JavaScript async function designed to populate a sudoku board with numbers, essentially solving the puzzle. To enhance the user experience and showcase the recursion and backtracking algorithm in action, a sleeper function is utilized b ...

BehaviorSubject Observable continuously notifies unsubscribed Subscription

Utilizing a service called "settings", initial persisted values are read and provided through an observable named "settings$" to components that subscribe to it. Many components rely on this observable to retrieve the initial values and exchange updated va ...

Utilize devextreme for uploading files

Currently, I am trying to implement an upload document feature using Dev-Extreme, but I keep encountering an error onFileUpload(event){ this.file = event.target.files[0] } <dxi-column [showInColumnChooser]="false" type="buttons" [width]="100 ...

Retrieving rows from a MySQL table that contain a specified BIGINT from an array parameter

I've encountered a problem with mysql while using serverless-mysql in TypeScript. It seems like my query might be incorrect. Here is how I am constructing the query: export default async function ExcuteQuery(query: any, values: any) { try { ...

gulp-tsc cannot locate the src directory

I am currently working on developing a .NET Core application using Angular2, but I keep encountering the following error: /wwwroot/NodeLib/gulp-tsc/src/compiler.ts' not found. I'm having trouble pinpointing what I might be missing. tsconfig.js ...

Nestjs is throwing an UnhandledPromiseRejectionWarning due to a TypeError saying that the function this.flushLogs is not recognized

Looking to dive into the world of microservices using kafka and nestjs, but encountering an error message like the one below: [Nest] 61226 - 07/18/2021, 12:12:16 PM [NestFactory] Starting Nest application... [Nest] 61226 - 07/18/2021, 12:12:16 PM [ ...

Angular2 restricts Http requests within a specified time interval

I am a beginner with angular 2 and I have a value that is linked to user interaction that needs to be sent over http requests. The value can change multiple times per second, so I want to limit the http requests to one every 2 seconds during user interacti ...

What is the correct way to exclude and remove a portion of the value within an object using TypeScript?

The function useHider was created to conceal specific values from an object with the correct type. For example, using const res = useHider({ id: 1, title: "hi"}, "id"), will result in { title: "hi" } being returned. Attempting ...

The text inside the Mapbox GL popup cannot be highlighted or copied

I'm encountering an issue where the text in my popups is unselectable. Even though I can close the popups through various methods, such as clicking on them, the pointer remains as a hand icon when hovering over the text and doesn't change to the ...

Creating TypeScript Unions dependent on a nested object's property

I want to create a Union Type that is dependent on a nested property within my object. Take a look at the example provided below: type Foo = { abilities: { canManage: boolean } } type Bar = { abilities: { canManage: boolean ...

Implementing TypeScript module resolution with Cucumber-js can be a bit tricky

Currently, I am in the process of creating a Proof of Concept for Cucumber-js using TypeScript. Everything is going smoothly except for one issue - I am facing difficulties when it comes to configuring the module resolution while utilizing tsconfig-paths. ...

Loading data into the Nuxt store upon application launch

Currently, I'm working on an app using Nuxt where I preload some data at nuxtServerInit and store it successfully. However, as I have multiple projects with similar initial-preload requirements, I thought of creating a reusable module for this logic. ...