skip to Main Content

How can I define a map where each key has a certain type assigned ?

This is the type def:

type Data = {
  articles: Article[],
  comments: Comment[],
  ...
}

And the map def has to accept only keys from that type, but the values have to match the keys:

type MyMap = <K extends keyof Data>Map<K, Data[K]>; // <- doesn't work

2

Answers


  1. You can make a generic type, that uses a distributed conditional type

    type MyMap<O, K extends keyof O = keyof O> = K extends any ? Map<K, O[K]> : never;
    

    This builds a union of Map types for each key (K) from Data and with the associated value type (O[K]):

    type MyDataMap = MyMap<Data>;
    // Map<"articles", Article[]> | Map<"comments", Comment[]>
    

    To break it down a little, the MyMap<Data> is the same as MyMap<Data, keyof Data> (due to the default on the second generic type). keyof Data can also be written as a union type of "articles" | "comments":

    MyMap<Data>
    // "unfurls" to 
    MyMap<Data, "articles" | "comments">
    // O--^^^^   ^^^^^^^^^^^^^^^^^^^^^----- K
    

    The conditional type of K extends any is then applied to each member of the "articles" | "comments" union. So MyMap distributes on each element, effectively giving:

    MyMap<Data, "articles"> | MyMap<Data, "comments">
    

    When ultimately gives:

    Map<"articles", Article[]> | Map<"comments", Comment[]>
    
    Login or Signup to reply.
  2. I think what you’re looking for is something like the following:

    interface StrictMap<T extends Record<string, any>>
      extends Map<keyof T, T[keyof T]> {
      clear(): void;
      delete(key: keyof T): boolean;
      get<K extends keyof T>(key: K): T[K] | undefined;
      has(key: keyof T): boolean;
      set<K extends keyof T>(key: K, value: T[K]): this;
      readonly size: number;
    }
    

    This is a copy of the Map type, but I have changed the generics to accept only an object-like value (which will retain the exact key-value mappings).

    I have also overridden most of the methods so that the types are stricter. The only one I have left out is forEach which uses the existing Map.forEach as our new type extends the Map<K, V> type.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search