TypeScript: Add typing to the lodash entries helper

This is a followup post to the other one where we’ve added types to the lodash keys helper. This time we will add types to the entries helper, which is an alias to the toPairs helper, where we can also benefit from the proper typing of the returned list of key, value pairs. Let’s start with the same setup as in the other post:

import { entries } from "lodash";

// test object upon which we will call keys
type TObject = {
  fieldNum: number;
  fieldStr: string;
  fieldBln: boolean;
  fieldArr: string[];
}

const o: TObject = {
  fieldNum: 42,
  fieldStr: 'greladesign',
  fieldBln: true,
  fieldArr: ["a", "b", "c"]
};

// tooltip will show: const entryPairs: [string, string | number | boolean | string[]][]
const entryPairs = entries(o);

//
entryPairs.forEach((pair /* : [string, string | number | boolean | string[]] */): void => {
  // You have lost the information about keys of the object, 
  // TypeScript will no longer be able to verify field for you
  if (pair[0] === 'fieldBoolean') { // TS will accept this incorrect field name
    const flag = pair[1] // TS will use a union of all value types it found on object
    // which is string, string | number | boolean | string[]
  }
})
Code language: TypeScript (typescript)

Sorting out the type of pair[0] is fairly simple to resolve:

// add following to your typings e.g. lodash-override.d.ts
export {};

declare module 'lodash' {
  interface LoDashStatic {
    toPairs<O, K extends keyof O = keyof O>(object?: O): [K, O[K]][];
    entries<O, K extends keyof O = keyof O>(object?: O): [K, O[K]][];
  }
}
Code language: PHP (php)

This helps a bit, keys are correctly picked up from the object

// tooltip will now show: const entryPairs: [keyof TObject, string | number | boolean | string[]][]
const entryPairs = entries(o); 

//
entryPairs.forEach((pair /* : [keyof TObject, string | number | boolean | string[]] */): void => {
  // TS will now correctly identify this as an error
  // if (pair[0] === 'fieldBoolean'){ 
  // After correcting the field name we're good
  if (pair[0] === 'fieldBln') {
    const flag = pair[1] // This still is a union of all value types
  }
})
Code language: TypeScript (typescript)

The problem is still with the value of the pair. TypeScript doesnt know how to map it and it takes all of them as union. We need to let TS know how to infer the type by the used key.

Let’s prepare a helper type that will produce correctly typed tuple.

type TTuple<O> = {
  /* map the possible tuples against object's field */
  [Field in keyof O]: [field: Field, value: O[Field]];
}/* select the proper tuple */[keyof O];


const tuple: TTuple<TObject> = ['fieldBln', true];

// tooltip over tuple shows const tuple: [field: "fieldBln", value: boolean]
const key = tuple[0];
const value = tuple[1];
Code language: TypeScript (typescript)

We have a helper that will select correct type for the value based on the selected field.

Let’s adjust the lodash typing:

// add following to your typings e.g. lodash-override.d.ts
export {};

type TTuple<O> = {
  [Field in keyof O]: [field: Field, value: O[Field]];
}[keyof O];

declare module 'lodash' {
  interface LoDashStatic {
    toPairs<O>(object?: O): TTuple<O>[]; 
    entries<O>(object?: O): TTuple<O>[]; 
  }
}
Code language: TypeScript (typescript)

Now we’re all set and you can have properly typed entries. I hope you’ll find it useful.

Source code

This entry was posted in TypeScript and tagged . Bookmark the permalink.