Skip to content

Instantly share code, notes, and snippets.

@gund
Last active February 28, 2019 19:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gund/458b8d48e6c2fed6c561c088f96f2be8 to your computer and use it in GitHub Desktop.
Save gund/458b8d48e6c2fed6c561c088f96f2be8 to your computer and use it in GitHub Desktop.
Helper to produce indexed objects from arrays by key
type GetValTypeIfNot<T, D> = T extends { [k: string]: infer V } ? (V extends D ? never : T) : never;
interface IndexableByDeletedProp {
__IndexableByDeletedProp: true;
}
type IndexedBy<TA extends Array<any>, K extends keyof T, T = TA[number]> = {
[P in T[K]]: GetValTypeIfNot<
{ [PP in keyof T]: T[K] extends P ? T[PP] : IndexableByDeletedProp },
IndexableByDeletedProp
>
};
// Example:
const arr = [
{ id: '1' as '1', name: 'n1', surname: 'sn1' },
{ id: '2' as '2', name: 'n2' },
{ id: '3' as '3' },
];
const a: IndexedBy<typeof arr, 'id'> = arr.reduce(indexBy('id')); // indexBy function is same as in indexable.ts
const a1 = a['1'];
const a2 = a['2'];
const a3 = a['3'];
const b1 = a1.name;
const b2 = a2.name;
const b3 = a3.name;
declare global {
interface Array<T> {
reduce<U>(
callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U,
): U;
}
}
type IndexedBy<T, K extends keyof T> = T[K] extends string | number | symbol
? Record<T[K] extends number ? string : T[K], T>
: never;
export const indexBy = <T, K extends keyof T>(key: K) => (
acc = {} as IndexedBy<T, K>,
val: T,
): IndexedBy<T, K> => {
(acc as any)[val[key]] = val;
return acc;
};
// Example:
const arr = [
{id: '1', val: ''},
{id: '2', val: ''},
{id: '3', val: ''},
];
const indexedArr = arr.reduce(indexBy('id'));
// indexedArr['2'] will return arr[1]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment