Home > database >  Map a return type as the union of an input type and a list of property values from an array in Types
Map a return type as the union of an input type and a list of property values from an array in Types

Time:09-30

I have a function that I have declared as follows:

export const buildLocalizedInfo = <T extends { id: number }, U extends { target: string }>(
    recordBuilder: (record: any) => T,
    propsMapper: readonly U[],
): T

and that I use like this:

const bounties = buildLocalizedInfo(
    (record) => ({
        id: record['m_ID'],
    }),
    [{ target: 'name' }],
);

I want to have the return type of buildLocalizedInfo to be T & {name: string}, except that it should also extends to whatever properties I pass in the input array.

For instance,

const bounties = buildLocalizedInfo(
    (record) => ({
        id: record['m_ID'],
        other: record['other'],
    }),
    [{ target: 'name' }, { target: 'description' }],
);

should resolve bounties to be of type { id: string; other: string; name: string; description: string}.

Is this possible in typescript?

CodePudding user response:

Yes, you just need to intersect the result with a mapped type of the elements, but since you're mapping them all to strings, a Record will do just fine:

export const buildLocalizedInfo = <T extends { id: number }, U extends { target: string }>(
    recordBuilder: (record: any) => T,
    propsMapper: readonly U[],
): T & Record<U["target"], string>;

However, you'll probably need as const with this. If you don't like that, then you can use this instead:

type Narrow<T> =
    | (T extends infer U ? U : never)
    | Extract<T, number | string | boolean | bigint | symbol | null | undefined | []>
    | ([T] extends [[]] ? [] : { [K in keyof T]: Narrow<T[K]> });

export const buildLocalizedInfo = <T extends { id: number }, U extends readonly { target: string }[]>(
    recordBuilder: (record: any) => T,
    propsMapper: Narrow<U>,
): T & Record<U[number]["target"], string>;

This Narrow utility will narrow the type for us, which you can see here.

  • Related