skip to Main Content

I am unable to create union type from Map. Here is a simple example of what I am trying to do:

const myMap = new Map ([
  ['one', <IconOne/>],
  ['two', <IconTwo/>],
  ['three', <IconThree/>],
]);
// I know i can make it not like Map. But I have data like Map, and can't change it now.

type Props = {
  name: 'one' | 'two' | 'three'; 
  // i need this type here, but have no idea how to make this type from map keys
  // tryed use "typeof" "keyof" but have no idea how to do it right 
}

export const Component = ({name}: Props) => (
   <div>
    {myMap.get(name)}
   </div>
) 

2

Answers


  1. You will need to change the Map definition to use as const (otherwise you just get string as the key type), then you can write

    const myMap = new Map ([
      ['one', <IconOne/>],
      ['two', <IconTwo/>],
      ['three', <IconThree/>],
    ] as const);
    
    type Props = {
      name: typeof myMap extends Map<infer K, any> ? K : never;
    }
    
    Login or Signup to reply.
  2. See the correct answer from @Bergi: https://stackoverflow.com/a/77887764/15076557

    Below is my attempt to an answer — maybe other methods I provided will be helpful to someone else.


    I don’t think you can do this with your setup.

    If you look at the type of myMap, it will be Map<string, string> — typescript doesn’t narrow this type to any of your keys or values. So, even a solution like in this answer would not help, meaning you likely will have to bring out the data you pass to Map to some variable/type in one way or another.


    Now, one of the closest solutions might be taking out the keys to a separate type and then using it in myMap and Props:

    type Key = 'one' | 'two' | 'three';
    
    const myMap = new Map<Key, string> ([
      ['one', '123'],
      ['two', '456'],
      ['three', '345'],
    ]);
    // I know i can make it not like Map. But I have data like Map, and can't change it now.
    
    type Props = {
      name: Key; 
      // i need this type here, but have no idea how to make this type from map keys
      // tryed use "typeof" "keyof" but have no idea how to do it right 
    }
    

    Another way is to define the keys and values using an array and as const assertion to narrow the types, and infer them into a separate type, and once again use it in myMap and Props:

    const myMapAsArr = [
      ['one', '123'],
      ['two', '456'],
      ['three', '345'],
    ] as const;
    
    type Key = typeof myMapAsArr[number][0];
    
    const myMap = new Map(myMapAsArr);
    
    type Props = {
      name: Key;
      // i need this type here, but have no idea how to make this type from map keys
      // tryed use "typeof" "keyof" but have no idea how to do it right 
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search