Как написать тип для объекта аккумулятора в Array.prototype.reduce, когда аккумулятор является объектом? - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть эти типы в моем коде:

    export interface KeyValue {
      [key: string]: any
    }

    export type FormErrors<V extends KeyValue> = {
      [K in keyof V]: string[]
    }

    export function getInitialErrors<V extends KeyValue> (data: V): FormErrors<V> {
      return Object.keys(data).reduce((acc, key) => (
        { ...acc, [key]: [] }
      ), {} as FormErrors<V>) // eslint-disable-line @typescript-eslint/consistent-type-assertions
    }

Мой вопрос: как я могу удалить прямое приведение типов для аккумулятора в такой ситуации?

Я думаю, что для достижения этого я уже должен иметь объект по умолчанию с типом FormErrors<V>. Но проблема в том, что функция getInitialErrors должна создать такой объект по умолчанию.

1 Ответ

2 голосов
/ 24 апреля 2020

Основная проблема, с которой вы столкнулись в настоящее время, состоит в том, что тип FormErrors говорит, что он имеет ключ, соответствующий каждому ключу V, и до тех пор, пока не завершится редукция, это не так.

У вас есть пара параметры:

  • Передайте обобщенные значения, чтобы уменьшить, чтобы сделать тип возвращаемого значения Partial<FormErrors<V>>, и приведите к FormErrors в конце:

    export function getInitialErrors<V extends KeyValue> (data: V): FormErrors<V> {
        return Object.keys(data).reduce<Partial<FormErrors<V>>>((acc, key) => (
            { ...acc, [key]: [] }
        ), {}) as FormErrors<V>
    }
    

    Вы можете просто немного теперь отбрасываем возвращаемый тип функции, так как он все равно четко определен приведением. Это, пожалуй, самый правильный вариант (он действительно является частичным во время сокращения, и тогда вы четко заявляете, что думаете, что теперь он завершен только в конце), но он немного грязный.

  • Установите тип acc на Partial<FormErrors<V>> (т. Е. Укажите реальный тип acc). Это немного удивляет меня, но это, кажется, работает:

    export function getInitialErrors<V extends KeyValue> (data: V): FormErrors<V> {
        return Object.keys(data).reduce((acc: Partial<FormErrors<V>>, key) => (
            { ...acc, [key]: [] }
        ), {})
    }
    

    Это довольно хороший баланс между корректностью и читабельностью imo.

  • Сделайте ключи в FormErrors необязательно (т.е. сделать это [K in keyof V]?: string[]). Это работает и делает ваш код полностью корректным, но может не работать для остальной части вашего приложения.

  • Приведите {}, как вы делаете сейчас. Это работает, но вы фактически лжете компилятору заранее (в начале, это действительно не полный FormErrors), а затем исправляете его позже, прежде чем что-то действительно сломается.

Какой из них вы хотите Выбор зависит от вашего варианта использования, но я думаю, что это основные варианты.

...