Как правильно использовать функции-аргументы?

Изучаю TypeScript, и появилась необходимость типизировать одну из функций:
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());

На TypeScript переписал следующим образом:
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());

Но при использовании появилась проблема - как правильно использовать возвращаемый тип (ReturnType) функции, которая была передана в функцию groupBy. Пример:
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[]>

Как необходимо исправить тип аргумента extractor, чтобы использовать тип string, возвращаемый данной функцией?
  • Вопрос задан
  • 156 просмотров
Решения вопроса 1
WblCHA
@WblCHA
Ты же используешь T[keyof T] и передаёшь
interface IUser {
    name: string;
    role: IRole;
}

Вот на выходе и получается 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[]>());
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы