dwjohnston
dwjohnston

Reputation: 11890

Reference an index type while creating a mapped type?

I have a scenario where I have a union of different types that all have a similar signature. I want to create a mapped type so I can look up all my types by an id:

type Apple = {
    name: "apple", 
    value: 1, 
}; 

type Banana = {
    name: "banana", 
    value: "foobar"
}; 

type Cherry = {
    name: "cherry", 
    value: () => "hi"
}; 

type AllTypes = Apple | Banana | Cherry; 

type AllTypeKeys = AllTypes['name']; 


type TypeMap = {
    "apple": Apple; 
    "banana": Banana; 
    "cherry": Cherry; 
}

I can do it manually, as I have done in the TypeMap.

However, I would prefer to do something like this:

type TypeMap = {
   [F['name'] in AllTypes]: F; 
}

This obviously doesn't work. Is there something similar that would?

Upvotes: 4

Views: 59

Answers (1)

Teneff
Teneff

Reputation: 32148

As of TypeScript 4.1 you can use Key Remapping via as

type TypeMap2 = {
  [K in AllTypes as K['name']]: K
}

playground


Prior to TypeScript 4.1 you can use Extract

type TypeMap = {
  [V in AllTypes['name']]: Extract<AllTypes, { name: V }>
}

playground


More generic type can be defined as

type MapByKey<T, U extends keyof T > = {
  [K in T as K[U] & (string | number | symbol)]: K
}


// or prior to TS 4.1
type MapByKey<T, U extends keyof T > = {
  [V in T[U] & (string | number | symbol)]: Extract<T, Record<U, V>>
}

type TypeMap3 = MapByKey<AllTypes, 'name'>

playground

Upvotes: 2

Related Questions