Adrian Locurcio
Adrian Locurcio

Reputation: 58

How to add complex types to a specific function

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

Answers (1)

CertainPerformance
CertainPerformance

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

Related Questions