I have some utility functions that I want to add generic types to in typescript but can't figure out how to do it.
(These are based on the functionality of ramda but I don't want to use ramda in this project.)
pick :
function pick(keys, object) {
const result = Object.assign(
{},
...keys.map(k => (k in object ? { [k]: object[k] } : {}))
);
return result;
}
reject :
function reject(keys, object) {
const result = Object.assign(
{},
...Object.keys(object)
.filter(k => !keys.includes(k))
.map(k => ({ [k]: object[k] }))
);
return result;
}
}
... I'd like to use them like this and have typescript work out the resultant type :
type Item = {title: string, description: string}
const test: { [key: string]: Item } = {
a: { title: 'TitleA', description: 'DescriptionA' },
b: { title: 'TitleB', description: 'DescriptionB' },
c: { title: 'TitleC', description: 'DescriptionC' },
d: { title: 'TitleD', description: 'DescriptionD' }
};
const test1 = pick(['a', 'c'], test) // {a: { title: 'TitleA', description: 'DescriptionA' }, c: { title: 'TitleC', description: 'DescriptionC' }}
const test2 = reject(['a', 'c'], test) // {b: { title: 'TitleB', description: 'DescriptionB' },d: { title: 'TitleD', description: 'DescriptionD' }}
Does anyone have a suggestion of how to add generic typing to these
pick
andreject
functions?
You can use two generic type parameters, one for the object itself and one for the picked keys. Then you can add a type boundary to the keys to be a subset of the object keys. The return type is then a mapped type of the keys looked up on the object:
function pick<O, K extends keyof O>(keys: K[], object: O): { [T in K]: O[T] }
The reject
function can be typed similarily:
function reject<O, K extends keyof O>(keys: K[], object: O): { [T in keyof O]: T extends K ? undefined : O[T] }