Reputation: 58
I'm trying to add types to this function
function getNewObjectFromKeys(source, keys) {
return keys.reduce((acum, value) => {
if(typeof source[value] !== 'undefined') {
return {
...acum,
[value]: source[value]
}
}
return acum;
}, {});
}
This function only returns a new object from argument source
with specified keys from argument keys
.
I was trying something like this
function getObjectWithKeys<K extends object, T extends keyof K>(source: K, keys: T[]): Pick<K, typeof keys[number]> {
return keys.reduce((acum, value) => {
if(typeof source[value] !== 'undefined') {
return {
...acum,
[value]: source[value]
}
}
return acum;
}, {}) as Pick<K, typeof keys[number]>;
}
But that as Pick<K, typeof keys[number]>
is not convincing me, could this typing strategy be improved ?
I couldn't accomplish this passing a type as generic param on reduce
method. Any help ? Thanks!
Upvotes: 2
Views: 78
Reputation: 370689
typeof keys[number]
is exactly equivalent to your T
type, so you can replace it with:
as Pick<K, T>;
But Object.fromEntries
might look nicer - reduce
is pretty verbose, ugly when the accumulator is an object in TypeScript, and arguably not appropriate for this sort of situation even in JavaScript.
function getObjectWithKeys<K extends object, T extends keyof K>(source: K, keys: T[]) {
return Object.fromEntries(
keys.map(
key => [key, source[key]]
)
) as Pick<K, T>;
}
const result = getObjectWithKeys({ foo: 'foo', bar: 'bar' }, ['foo'])
results in result
being typed as
const result: Pick<{
foo: string;
bar: string;
}, "foo">
To also filter out undefineds, you can .filter
after mapping:
keys.map(
key => [key, source[key]]
)
.filter(
[, value] => value !== undefined
)
Upvotes: 3