typescripttypescript-genericsmapped-types

How can I get the inverse of a TypeScript mapped type?


I am looking to get the "inverse" of a TypeScript mapped type (whose properties are strictly strings, so as to be "inversible"). To illustrate my desired result, I need a generic type

type Inverse<M> = ...

to be able to transform

type MappedType = {
  key1: 'value1'
  key2: 'value2'
};

into

/**
 * {
 *   value1: 'key1';
 *   value2: 'key2';
 * }
 */
type MappedTypeInverse = Inverse<MappedType>

I've tried a couple things already.. but to no avail:

type Inverse<M> = M extends Record<infer O, infer T> ? Record<T, O> : never;

/**
 * type MappedTypeInverse = {
 *   value1: 'key1' | 'key2'
 *   value2: 'key2' | 'key2'
 * }
 */
type MappedTypeInverse = Inverse<MappedType>
type InverseValue<M extends Record<any, any>, V extends M[keyof M]> = V extends M[infer K] ? K : never;

/**
 * type MappedTypeInverseValue = unknown // expecting 'key1'
 */
type MappedTypeInverseValue = InverseValue<MappedType, 'value1'>

Is this even possible? Any help would be appreciated!


Solution

  • Here is a lean alternative (in addition to Patrick Robert's good solution):

    type KeyFromVal<T, V> = {
      [K in keyof T]: V extends T[K] ? K : never
    }[keyof T];
    
    // we assume the type to be an object literal with string values
    // , should also work with number or symbol
    type Inverse<M extends Record<string, string>> = {
      [K in M[keyof M]]: KeyFromVal<M, K>
    };
    
    type MappedType = {
      key1: 'value1'
      key2: 'value2'
    };
    
    type MappedTypeInverse = Inverse<MappedType> // { value1: "key1"; value2: "key2"; }