Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the key of a value in a Typescript Record

Here's the code:

export type Period = 'dy' | 'wk' | 'mn' | 'qt' | 'yr';

const periods: Record<Period, string> = {
    dy: 'Day',
    wk: 'Week',
    mn: 'Month',
    qt: 'Quarter',
    yr: 'Year'
  };

When I try to do this:

const key = Object.keys(periods).find(key => periods[key] === 'Day');

I get an error of course, since periods[key] cannot guarantee that key is of the correct type. How should I really go about doing this? I thought of an enum but I can't do reverse lookups. All I'm trying to achieve is an input field that displays 'Day' but has a key of dy (etc.) and can set the state to the correct key and not the value when the user picks another value.

like image 782
Sammy Avatar asked Nov 19 '19 07:11

Sammy


People also ask

How do you get keys in TypeScript?

How to get the keys of a TypeScript interface? To get the union of the keys of a TypeScript interface, we can use the keyof keyword. interface Person { name: string; age: number; location: string; } type Keys = keyof Person; to create the Keys type by setting it to keyof Person .

How do you define a key-value in TypeScript?

Use an index signature to define a key-value pair in TypeScript, e.g. const employee: { [key: string]: string | number } = {} .


2 Answers

Object.keys returns string[] not Array<keyof T> (where T is the type of the value passed in). The reasons for this are outlined here.

Since your object is probably not going to have unknown keys, you can use a type assertion:

export type Period = 'dy' | 'wk' | 'mn' | 'qt' | 'yr';

const periods: Record<Period, string> = {
  dy: 'Day',
  wk: 'Week',
  mn: 'Month',
  qt: 'Quarter',
  yr: 'Year'
};

const key = (Object.keys(periods) as Array<Period>).find(key => periods[key] === 'Day');

Playground Link

like image 188
Titian Cernicova-Dragomir Avatar answered Sep 22 '22 12:09

Titian Cernicova-Dragomir


I have found myself needing to solve this many times. I have some utils laying around that help.

This is what I would do.

const _periods = {
  dy: 'Day',
  wk: 'Week',
  mn: 'Month',
  qt: 'Quarter',
  yr: 'Year',
} as const;

export type Period = keyof typeof _periods;
export type PeriodValue = typeof _periods[Period];

export const periods = _periods as Record<Period, PeriodValue>;

function keys<T>(object: T) {
  return Object.keys(object) as (keyof T)[];
};

const key = keys(periods).find((key) => periods[key] === 'Day');

// Compile error, value not possible.
const badValueKey = keys(periods).find((key) => periods[key] === 'Minute');
like image 35
Daniel Raby Avatar answered Sep 21 '22 12:09

Daniel Raby