Skip to content

Instantly share code, notes, and snippets.

@simlrh
Last active March 2, 2021 17:45
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 simlrh/bf901a81c132c4ba09d433938c558e76 to your computer and use it in GitHub Desktop.
Save simlrh/bf901a81c132c4ba09d433938c558e76 to your computer and use it in GitHub Desktop.
Miscellaneous TypeScript helpers
// Wrapper for Object.keys which sets the correct type
export function getKeys<T>(obj: T): Array<keyof T> {
return Object.keys(obj) as Array<keyof T>;
}
/**
* Usage:
*
* const normalize = mapArrayToObject(obj => ({ [obj.id]: { ...obj, name: obj.name.toLowerCase() } }));
* normalize(objects);
*/
export function mapArrayToObject<
T,
Key extends number | string | symbol,
Value
>(fn: (t: T) => { [key in Key]: Value }) {
return function(array: T[]): { [key in Key]: Value } {
return Object.assign({}, ...array.map(fn));
};
}
function mapArrayToObjectWithPropAsKey<
K extends string | number | symbol,
>(keyProp: K) {
return function<T extends { [key in K]: string | number | symbol }>(array: T[]): { [key in T[K]]?: T } {
return Object.assign({}, ...array.map((t: T) => ({ [t[keyProp]]: t })));
};
}
interface Task {
id: 1 | 2 | 3 | 4;
text: string;
}
const tasks: Task[] = [
{ id: 1, text: 'To do 1' },
{ id: 2, text: 'To do 2' },
{ id: 3, text: 'To do 3' },
];
const normalize = mapArrayToObjectWithPropAsKey('id');
const state = normalize(tasks); // type: { [id: 1 | 2 | 3 | 4]?: Task }
type MapObjIndexedFn<T, TResult> = (
value: T,
key: string,
obj?: {
[key: string]: T;
},
) => TResult;
export function mapObject<K extends string, T, TResult>(
fn: MapObjIndexedFn<T, TResult>,
obj: { [key in K]: T },
): { [key in K]: TResult } {
return getKeys(obj).reduce(
(acc, key) => {
acc[key] = fn(obj[key], key.toString(), obj);
return acc;
},
{} as { [key in K]: TResult },
);
}
const tasks = {
todo1: { id: 1, text: 'To do 1' },
todo2: { id: 2, text: 'To do 2' },
todo3: { id: 3, text: 'To do 3' },
};
const taskTexts = mapObject(task => tast.text, tasks);
// { todo1: 'To do 1', todo2: 'To do 2', todo3: 'To do 3' }
function prop<K extends string | number | symbol>(key: K) {
return function<V>(obj: { [key in K]: V }): V {
return obj[key];
}
}
const tasks = [
{ id: 1, text: 'To do 1' },
{ id: 2, text: 'To do 2' },
{ id: 3, text: 'To do 3' },
];
const ids = tasks.map(prop('id'));
const texts = tasks.map(prop('text'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment