A
A
Alexander2021-01-30 13:09:31
typescript
Alexander, 2021-01-30 13:09:31

What is the correct way to use argument functions?

Good day. I'm learning TypeScript and I need to type one of the following functions:

const groupBy = (collection, extractor) => collection.reduce((accumulator, entry) => {
    const key = extractor(entry);
    if (!accumulator.has(key)) {
        accumulator.set(key, []);
    }
    accumulator.get(key).push(entry);

    return accumulator;
}, new Map());

Rewritten in TypeScript as follows:
type Extractor<T> = (entry: T) => T[keyof T];

const groupBy = <T>(
    collection: T[],
    mapper: Extractor<T>
): Map<ReturnType<Extractor<T>>, T[]> => collection.reduce((accumulator, entry) => {
    const key = mapper(entry);
    if (!accumulator.has(key)) {
        accumulator.set(key, []);
    }
    accumulator.get(key).push(entry);

    return accumulator;
}, new Map());

But when using it, a problem arose - how to correctly use the return type ( ReturnType) of the function that was passed to the groupBy. Example:
interface IRole {
    name: string;
    power: number;
}

interface IUser {
    name: string;
    role: IRole;
}

const users: IUser[] = [
    {
        name: 'Andry',
        role: {
            name: 'admin',
            power: 127
        }
    },
    {
        name: 'Alex',
        role: {
            name: 'admin',
            power: 127
        }
    },
    {
        name: 'John',
        role: {
            name: 'guest',
            power: 1
        }
    }
];

type Extractor<T> = (entry: T) => T[keyof T];

const groupBy = <T>(
    collection: T[],
    mapper: Extractor<T>
): Map<ReturnType<Extractor<T>>, T[]> => collection.reduce((accumulator, entry) => {
    const key = mapper(entry);
    if (!accumulator.has(key)) {
        accumulator.set(key, []);
    }
    accumulator.get(key).push(entry);

    return accumulator;
}, new Map());

const groupedUsers = groupBy(users, user => user.name[0].toUpperCase()); // Map<string | IRole, IUser[]>

How do you fix the type of the argument extractorto use the type stringreturned by this function?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
W
WbICHA, 2021-01-30
@Seasle

You use T[keyof T]and share

interface IUser {
    name: string;
    role: IRole;
}

Here is the output and it turns out string | IRole.
type Extractor<T, X> = (entry: T) => X;

const groupBy = <T, X>(
    collection: T[],
    mapper: Extractor<T, X>
): Map<X, T[]> => collection.reduce((accumulator, entry) => {
    const key = mapper(entry);
    if (accumulator.has(key)) {
        accumulator.get(key)!.push(entry);
    
        return accumulator;
    }

    accumulator.set(key, [entry]);

    return accumulator;
}, new Map<X, T[]>());

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question