Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript - Looping through keys for mapped Type

Tags:

typescript

Is there a better method than the following for looping through the keys of an object and return a new object with the same key but the values transformed and ensuring the resulting type contains that 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
like image 542
kimsagro Avatar asked Mar 21 '26 04:03

kimsagro


1 Answers

How about the following approach (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);

Steps:

  1. Object.entries(): returns an array of a given object's own enumerable string-keyed property [key, value] pairs.
  2. Array.prototype.reduce(): executes a reducer function on each element of the array.
    1. ({ ...acc, [key]: value.length }): returns the current accumulator (result object) with the new element (current) key: value(length).
    2. {} as OutputType<TEnv>: initilialize the accumulator as an empty object having the correct output type.

Typescript Playground

like image 68
Carlo Corradini Avatar answered Mar 23 '26 19:03

Carlo Corradini