Аргумент типа "только для чтения..." нельзя присвоить параметру типа "...[]"

Есть похожий вопрос, но проблема отличается от моей, найденной здесь Аргумент типа '...' нельзя присвоить параметру типа '...' TS 2345

utils.ts (https://www.typescriptlang.org/docs/handbook/2/generics.html#общие-типы)

export function getRandomItem<T>(array: T[]): T {
  return array[Math.floor(Math.random() * array.length)]
}

одежда.ts

import { getRandomItem } from "@/assets/ts/utils"

export const apparelLocation = ["HEAD", "TORSO", "ARMS", "LEGS"] as const
export type TypeApparelLocation = typeof apparelLocation[number]

// ...

export class Apparel {
  / ...
  location: TypeApparelLocation

  constructor(rating: number) {
    // ...
    this.location = getRandomItem(apparelLocation)
    }
  }

Выдаст ошибку внутри при использовании getRandomItem()

Argument of type 'readonly ["HEAD", "TORSO", "ARMS", "LEGS"]' is not assignable to parameter of type '("HEAD" | "TORSO" | "ARMS" | "LEGS")[]'. The type 'readonly ["HEAD", "TORSO", "ARMS", "LEGS"]' is 'readonly' and cannot be assigned to the mutable type '("HEAD" | "TORSO" | "ARMS" | "LEGS")[]'.ts(2345)

Что я пытаюсь сделать (в случае необходимости для лучшего понимания):

  1. создать переменную, содержащую массив с литеральными значениями
  2. создать объявление типа (объединение литералов) из этого массива (TypeScript: определить тип объединения из массива строк)
  3. использовать этот тип в качестве аннотации к атрибуту класса
  4. выберите случайный элемент из массива для назначения атрибуту location

Что касается того, почему мне нужна первая причина, потому что мне нужно сделать цикл где-то еще.

Несколько "исправлений", которые я нашел:

  1. удаление as const из apparelLocation помогло, но я могу присвоить местоположению любое значение, а не только эти 4
  2. удаление аннотации типа в функции и использование простого array: any также работает, но выдает предупреждение

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

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
0
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если кто-то не докажет, что я ошибаюсь, я понял, что typescript жалуется на то, что вы передаете неизменяемый массив в функцию, потому что параметр функции array является изменяемым и может быть отредактирован, а значение, которое вы передаете, является константой.

Лучшее решение - настроить параметр функции только для чтения:

function getRandomItem<T>(array: readonly T[]): T {
   // ...
}

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

Другим, менее приятным решением может быть редактирование вызова следующим образом:

this.location = getRandomItem([...apparelLocation])

Таким образом, вы передаете не исходный неизменяемый массив, а просто его копию, которую можно обрабатывать и которая согласуется с изменяемым параметром функции.

Боже мой, спасибо, я застрял здесь на день. Я мало времени уделял js, тем более ts. Другое дело, есть ли лучший способ реализации того, что я пытаюсь сделать, по сравнению с моим? Так как я приехал со своим из кусочков из интернета. Я читал о enum, но мне нужно сделать Object.values(), чтобы получить значение, если я использую строку для значения, а не только ключ (?)

ArnNied 23.04.2022 13:30

Честно говоря, у меня тоже нет большого опыта работы с typescript :) Однако, если вам нужно получить случайное значение, имеет смысл иметь все в массиве и использовать его так, как вы это сделали. Насколько я знаю, перечисления не являются реальными объектами javascript, поэтому вы не сможете выбрать из них случайное значение.

Drago96 23.04.2022 14:44

Другие вопросы по теме

Передача vscode во внешние функции
Firebase: Почему мой код использует только первый документ в моей коллекции?
Реагировать на ошибку машинописного текста - элемент неявно имеет любой тип, потому что выражение строки типа не может использоваться для индексирования типа {}
Как получить доступ к вложенным необязательным индексам из интерфейса
Почему машинописный текст не может контекстуально вывести эти типы промежуточного программного обеспечения
Передать конструктор класса как функцию в другом классе
React & clsx: добавьте имя класса, если текущий элемент в сопоставленном массиве является первым из нескольких элементов
Свойство «MathFun» отсутствует в типе «(x?: число, y?: число) => число», но требуется в типе «Func».
Получение строки типа не может быть назначено строке типа для компонента TS в сборнике рассказов
Как ввести useState для файлов?