(Number | undefined) [] не может быть присвоено Number [] - PullRequest
0 голосов
/ 05 мая 2020

У меня проблема с типами в машинописном тексте.

Итак, у меня есть массив идентификаторов сомов, которые я получаю от некоторых флажков. Этот массив также может быть пустым.

пример значений, которые могут быть возвращены из submit ():

const responseFromSubmit = {
1: {
  id: "1",
  value: "true"
  },
2: {
  id: "2",
  value: "false"
  },
3: {
  id: "3",
  value: "false"
  } 
};



const Ids: number[] = Object.values(submit()!)
  .map(formfield => {
    if (formfield.value === 'true') {
      return Number(formfield.id);
    }
  })
  .filter(id => id != undefined);

Таким образом, в этом случае идентификаторы будут Ids = [1].

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

if (ids.length > 0){
  ids = []
}

Через этот код постоянные идентификаторы имеют тип (Number | undefined) [], как я могу сделать так, чтобы он всегда был типа number [], даже если он пустой?

Вот решение, но оно мне совсем не нравится:

const Ids: number[] = Object.values(submit()!)
  .map(formfield => {
    if (formfield.value === 'true') {
      return Number(formfield.id);
    } else {
      return 0;
    }
  })
  .filter(id => id != 0);

В моем случае formfield.id будет никогда не имеют значения 0, поэтому можно отфильтровать все элементы со значением 0. Поэтому я бы не рекомендовал это решение. но эй, это работает, правда? ¯ \ _ (ツ) _ / ¯

Ответы [ 3 ]

1 голос
/ 05 мая 2020

Проблема

Основная проблема - подпись .filter(). Он будет всегда возвращать массив того же типа, с которого вы начали. Компилятор TypeScript не может гарантировать что-либо еще. Вот пример:

const arr/*: (string | number) */ = ["one", 2, 3, "four", 5, 6];

const numbers/*: number[]*/ = arr.filter(x => typeof x === "number");

console.log(numbers);

Ссылка на игровую площадку

Этот работает , если вы не учитываете типы, но он функционально эквивалентен следующему:

const arr/*: (string | number)[]*/ = ["one", 2, 3, "four", 5, 6];

const numbers/*: number[]*/ = arr.filter(x => x !== "one");

console.log(numbers);

Playground Link

В обоих случаях у вас есть массив смешанных типов и некоторая функция фильтрации. Чтобы гарантировать, что результатом будет только определенный c тип, вам необходимо изучить код и сделать выводы. Однако компилятор работает не так - вызов .filter() на Array<T | U> может снова дать только Array<T | U>, общий c не изменился.

Решение

Что можно сделать, это изменить порядок ваших .map и .filter. Вам нужно будет их переписать, но с точки зрения типов он будет работать правильно. Я также сделал logi c более связным - прямо сейчас вы double фильтруете неявно. map() преобразует только некоторые типы, но не другие, таким образом выполняя косвенный фильтр. Фактический вызов .filter() затем отсеивает несопоставленные / мягко отфильтрованные значения.

Правильный logi c и правильное сохранение типа, таким образом, будут следующими:

const Ids: number[] = Object.values(submit()!)
  .filter(formfield => formfield.value === 'true')
  .map(formfield => Number(formfield.id))

Ссылка на игровую площадку

Это более короткая и правильная форма логики c, которую вы хотите.

  • Реальное условие фильтрации formfield.value === 'true' извлекается само в .filter() вызов.
  • .filter() запускает первый , поэтому вы гарантированно получите одинаковые типы с точки зрения компилятора и , список которых вы только что уменьшили только для тех элементов, которые вас интересуют.
  • .map() не выполняет в точности то, для чего предназначено - отображение 1: 1 для каждого значения массива. Не нужно делать никаких лог c более сложных. Таким образом, ему не нужно беспокоиться о том, что правильно, а что нет, чтобы выполнить преобразование.
0 голосов
/ 05 мая 2020

Я не могу ответить на ваш вопрос напрямую, но позвольте мне предложить другой подход:

const ids = Object.keys( obj || {} )
      .reduce( function(acc,cur) {
                   if( obj[cur] ) acc.push(cur);
                   return acc
                },
                []
              )

Похоже, вы хотите извлечь подмножество значений из вашего объекта. Это вернет ключи, которые правдивы. Вместо acc.push(cur) вы хотели бы pu sh эквивалент Number(formfield.id). obj || {} вверху позволяет obj быть undefined.

0 голосов
/ 05 мая 2020

Попробуйте добавить:

    if (formfield.value === 'true') {
      return Number(formfield.id);
    }
    return null;

под return в if.

Полный код:

const Ids: number[] = Object.values(submit()!)
  .map(formfield => {
    if (formfield.value === 'true') {
      return Number(formfield.id);
    }
    return null;
  })
  .filter(id => id != undefined);

EDIT:

Лучший способ проверить, не определена ли одна переменная, - использовать оператор typeof:

typeof id !== 'undefined'
...