Почему TypeScript выводит тип 'never' при уменьшении массива с помощью concat?

Код говорит лучше языка, поэтому:

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), []);

Код очень глупый и возвращает скопированный массив...

TS жалуется на аргумент concat: TS2345: Аргумент типа 'string' не может быть назначен параметру типа 'ConcatArray'.

7 ответов

Решение

Я считаю, что это потому, что тип для [] предполагается, что never[], который является типом для массива, который ДОЛЖЕН быть пустым. Вы можете использовать приведение типа для решения этой проблемы:

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), [] as string[]);

Обычно это не будет большой проблемой, поскольку TypeScript хорошо справляется с задачей определения лучшего типа для назначения пустому массиву на основе того, что вы с ним делаете. Тем не менее, поскольку ваш пример "глупый", как вы говорите, TypeScript не может делать какие-либо выводы и оставляет тип как never[],

Лучшее решение, которое позволяет избежать приведения типа:

Введите accumulator ценность как string[]избегайте приведения типа к[]):

['a', 'b', 'c'].reduce((accumulator: string[], value) => accumulator.concat(value), []);

Поиграйте с этим решением на игровой площадке машинописного текста.

Примечания:

  1. Приведения типов следует по возможности избегать, потому что вы берете один тип и переносите его на другой. Это может вызвать побочные эффекты, поскольку вы вручную берете на себя управление преобразованием переменной в другой тип.

  2. Эта машинописная ошибка возникает, только еслиstrictNullChecks опция установлена ​​на true. Ошибка Typescript исчезает при отключении этой опции, но, вероятно, это не то, что вам нужно.

  3. Я ссылаюсь на все сообщение об ошибке, которое я получаю с помощью Typescript 3.9.2 здесь, чтобы Google нашел эту ветку для людей, которые ищут ответы (потому что сообщения об ошибках Typescript иногда меняются от версии к версии):

    No overload matches this call.
      Overload 1 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
     Argument of type 'string' is not assignable to parameter of type 'ConcatArray<never>'.
      Overload 2 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
     Argument of type 'string' is not assignable to parameter of type 'ConcatArray<never>'.(2769)
    

Для решения этой проблемы вам следует использовать дженерики.

      ['a', 'b', 'c'].reduce<string[]>((accumulator, value) => accumulator.concat(value), []);

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

Вы можете использовать универсальный тип, чтобы избежать этой ошибки.

Проверьте мой пример функции flatten:

      export const flatten = <T>(arr: T[]): T[] => arr.reduce((flat, toFlatten) =>
  (flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten)), [] as T[]);

Два других способа установить тип, который мне нравится больше, чем приведение типов (т.е.[] as string) является:

  • <string[]>[]
  • Array<string>(0)

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

      const alphabet = ['a', 'b', 'c']
let accumulatorArray: string[] = []

const reduction = alphabet.reduce((acc, curr) => {
    acc.concat(curr)
}, accumulatorArray)

ничего из вышеперечисленного не сработало для меня, даже с изменением файла tsconfig.json на «strict»: false, и мне удалось избежать поломки приложения только со следующим:

      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Другие вопросы по тегам