Skapa en objekttyp i Typescript som härleds från värdena i ett annat objekt med hjälp av en generisk typ


Hur kan du generiskt konstruera en typ som härstammar från ett objekt enligt formatet nedan:

export const IMMEDIATE_FAMILY_MEMBERS_LIST_FIELDS = [
  { name: 'Relationship', type: 'dropdown', options: FAMILY_MEMBERS.NAMES },
  { name: 'Full name of family member as shown in passport', type: 'text' },
  {
    name: 'Country family member lives in',
    type: 'dropdown',
    options: COUNTRY.NAMES,
  },
  {
    name: 'Immigration status in that country',
    type: 'dropdown',
    options: IMMIGRATION_STATUS_OPTIONS,
  },
] as const

I detta:

export type ImmediateFamilyMembersListType = Array<{
  Relationship: FamilyMembersType
  'Full name of family member as shown in passport': string
  'Country family member lives in': CountryType
  'Immigration status in that country': keyof typeof IMMIGRATION_STATUS_OPTIONS
}>

Förutom utan att skriva in det manuellt varje gång för varje objekt?

Här är mitt bästa försök, men det är varken generiskt eller fungerar A extends B ? string[] : string ens:

type ImmediateFamilyMembersListFieldsType = typeof IMMEDIATE_FAMILY_MEMBERS_LIST_FIELDS
type ImmediateFamilyMembersListType = Record<ImmediateFamilyMembersListFieldsType[number]['name'], ImmediateFamilyMembersListFieldsType[number]['type'] extends 'dropdown' ? string[] : string>[]

Istället blir det bara till:

type ImmediateFamilyMembersListType = Record<"Relationship" | "Full name of family member as shown in passport" | "Country family member lives in" | "Immigration status in that country", string>[]

Svar #1

Här har du util-typ:

enum FAMILY_MEMBERS {
    NAMES = 'names'
}

enum COUNTRY {
    NAMES = 'names'
}

enum IMMIGRATION_STATUS_OPTIONS { a = 'a' }

type Options = COUNTRY | IMMIGRATION_STATUS_OPTIONS | FAMILY_MEMBERS

type FamilyMembersType = {}
type CountryType = {}

export const IMMEDIATE_FAMILY_MEMBERS_LIST_FIELDS = [
    { name: 'Relationship', type: 'dropdown', options: FAMILY_MEMBERS.NAMES },
    { name: 'Full name of family member as shown in passport', type: 'text', options: '' },
    {
        name: 'Country family member lives in',
        type: 'dropdown',
        options: COUNTRY.NAMES,
    },
    {
        name: 'Immigration status in that country',
        type: 'dropdown',
        options: IMMIGRATION_STATUS_OPTIONS,
    },
] as const

export type ImmediateFamilyMembersListType = Array<{
    Relationship: FamilyMembersType
    'Full name of family member as shown in passport': string
    'Country family member lives in': CountryType
    'Immigration status in that country': keyof typeof IMMIGRATION_STATUS_OPTIONS
}>

type Values<T> = T[keyof T]

type Data = typeof IMMEDIATE_FAMILY_MEMBERS_LIST_FIELDS


type Elem = { readonly name: string; readonly type: string; readonly options: any }

type MapObject<El extends Elem> = {
    [P in Values<Pick<El, 'name'>> & string]: El['options']
}

type Mapper<Arr extends ReadonlyArray<Elem>, Result extends Record<string, any> = {}> =
    Arr extends []
    ? Result : Arr extends [infer H]
    ? H extends Elem
    ? Result & MapObject<H> : never : Arr extends readonly [infer H, ...infer Tail]
    ? Tail extends ReadonlyArray<Elem>
    ? H extends Elem
    ? Mapper<Tail, Result & MapObject<H>> : never : never : never

type Result = Mapper<Data>

Jag har gjort narr av vissa typer eftersom jag inte vet någonting om dem.

Jag har använt any på några ställen, känn dig fri att ersätta det med en meningsfull typ. Som jag sa, det är för att jag inte är medveten om alla begränsningar, men jag tror att Mapper-typen bör hjälpa dig