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.