Уменьшение массива и необязательные значения в машинописи - PullRequest
0 голосов
/ 25 апреля 2018

Скажем, у меня есть следующий складной интерфейс:

export interface Foldable<F> {
  reduce: <A>(fn: (b: A, a: A) => A, initial: A, foldable: F) => A;
}

И затем я хочу реализовать его для массива:

export const getArrayFold = <A>(): Foldable<Array<A>> => {
  return {
    reduce: (fn, initial, array) => {
      return array.reduce(fn, initial);
    }
  };
};

Но компилятор жалуется на:

Аргумент типа '(b: A, a: A) => A' нельзя назначить параметру типа '(previousValue: A, currentValue: A, currentIndex: number, массив: A []) =>А».Типы параметров 'a' и 'currentValue' несовместимы.Тип «А» нельзя назначить типу «А».Существуют два разных типа с этим именем, но они не связаны между собой.

Я не понимаю, как здесь существуют два разных типа A.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Есть две ошибки:

  • Необходимо указать тип массива.Вы не можете получить его из одного универсального Array<T>, вам нужно ввести и T, и Array<T>.
  • Ваш тип для функции, потребляемой reduce, не подходит.Правильно: (previousValue: A, currentValue: F) => A

Объяснение:

Если вы предоставите начальное значение с типом (например, string) для уменьшения функции, previousValueПараметр всегда совпадает с inital .

См. Официальное Декларация сокращения TypeScript :

interface Array<T> {
    reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: ReadonlyArray<T>) => U, initialValue: U): U;
}

Полныйкод (с рефакторингом)

interface Foldable<F, T> {
    reduce: <A>(
        fn: (previousValue: A, currentValue: T) => A,
        initial: A,
        foldable: F
    ) => A;
}

const getArrayFold = <T>(): Foldable<T[], T> => ({
    reduce(fn, initial, array) {
        return array.reduce(fn, initial);
    }
});

// Real implementation usage
const array: number[] = [1, 2, 3]
const initial: string = "";
const fn: (previousValue: string, currentValue: number) => string = (a, b) => a + b;

const newValue: string = getArrayFold().reduce(fn, initial, array);

См. код на TypeScript игровая площадка

0 голосов
/ 26 апреля 2018

Проще увидеть, что происходит, если вы измените имена универсальных типов:

export const getArrayFold = <R>(): Foldable<Array<R>> => {

Теперь вы получите Type 'R' is not assignable to type 'A'.array.reduce использует различные типы для текущего значения и предыдущего значения, поэтому у вас есть тип A (универсальный тип из вашего интерфейса) и тип R из вашей функции getArrayFold.

У вас нетфактически передается в универсальном типе A в reduce, поэтому он считает, что он является A от интерфейса, что, по сути, означает, что он не может определить, какой тип должен быть.

OneЯ нашел способ сделать это, чтобы ваш интерфейс мог указать тип A и F:

export interface Foldable<F, A> {
  reduce: (fn: (b: A, a: A) => A, initial: A, foldable: F) => A;

Теперь вы можете написать свою функцию массива как

getArrayFold = <R>(): Foldable<Array<R>, R>

Когда вы звоните, вы можете сделать

getArrayFold<string>().reduce((a, b) => a + b, '', ['hello', 'world']);

Это обеспечит вам безопасность типов, так что вы не сможете использовать 0 в качестве значения или .toFixed на a / bсвойства или тому подобное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...