Ошибка TypeScript при вводе значения в цикле шаблона через ключи объекта в Vue 3 (Nuxt 3)

В настоящее время я переношу приложение Nuxt с версии 2 на версию 3, а также добавляю TypeScript в стек. В одном из моих шаблонов компонентов я перебираю набор ключей неизвестных объектов, чтобы создать список входов радио или флажков.

<template
    v-for = "(optionValue, optionKey) in options"
    :key = "`filter-option-${optionKey}`"
>
    <input
        :id = "optionKey.toString()"
        v-model = "selection"
        class = "filter-options-input visually-hidden"
        :value = "optionKey"
        :name = "name"
        :type = "type"
    >
    <label
        :for = "optionKey.toString()"
        :class = "['filter-options-label', `is-${type}`]"
    >
        {{ optionValue }}
    </label>
</template>

Код создает необходимые поля, как и ожидалось, но я не могу исправить следующую ошибку TypeScript в атрибуте <input>s :value:

Литерал объекта не может иметь несколько свойств с одним и тем же именем. ц(1117)

Вот жалуется:

Определение типа для options выглядит так:

type Option = {
    [key: string]: string;
}

Фактические данные будут выглядеть так:

{
    "portrait":"Hochformat",
    "landscape":"Querformat",
    "square":"Quadratisch"
}

или вот так:

{
    "akane-akane": "Akane, Akane",
    "anita-staud": "Staud, Anita",
    "anne-marie-chatelier": "Chatelier, Anne-Marie",
    "anneli-schuetz": "Schütz, Anneli",
    "annette-gundermann": "Gundermann, Annette",
    "arno-mohr": "Mohr, Arno",
    ...
}

Что TypeScript хочет сказать мне здесь и как я могу исправить сообщение об ошибке?

Вот репродукция в Codesandbox: https://codesandbox.io/p/sandbox/agitated-mendeleev-ypytew?file=%2Fcomponents%2Finput-list.vue&selection=%5B%7B%22endColumn%22%3A14% 2C%22endLineNumber%22%3A34%2C%22startColumn%22%3A14%2C%22startLineNumber%22%3A34%7D%5D

Спасибо за ваш ответ, но поскольку я использую здесь радио и флажки, мне нужно установить значение, чтобы Vue знал, какое значение установлено, когда использование выбирает одно из них. Например, как описано здесь: vuejs.org/guide/essentials/forms.html#checkbox. В противном случае я бы просто получал «включено» в качестве значения для каждого ввода.

Hermann Dettmann 15.02.2023 00:17

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

nicholasnet 15.02.2023 01:18

Но в вашем случае optionKey это объект, который, я думаю, вам нужно сделать optionKey.key вы пробовали это?

nicholasnet 15.02.2023 01:39

Спасибо @nicholasnet, как сказано, код действительно работает. Я использую здесь v-for, как описано для объектов (vuejs.org/guide/essentials/list.html#v-for-with-an-object), поэтому optionKey на самом деле просто ключ, а не сам объект. Мне просто интересно, почему TypeScript жалуется и как я могу это решить.

Hermann Dettmann 15.02.2023 09:51
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
4
102
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Проблема:
связано с неправильным вводом v-model как псевдонима InputHTMLAttributes.value. Согласно документам, v-model на

<input type = "checkbox"> и <input type = "radio"> используют свойство checked...

... который не имеет ничего общего со свойством value.


Сначала я подумал, что это исходит от nuxt (потому что это была единственная зависимость в песочнице, которую вы связали, и я не вижу того же в новом проекте vue), поэтому я открыл этот тикет в их репозитории.

Однако оказывается, что виновником неправильного ввода является Volar, расширение IDE, используемое Codesandbox (и, скорее всего, вашей IDE).

Если вы хотите продолжить это, не стесняйтесь поднимать вопрос с Volar в их репо.


Исправления:

  1. Отключить волар
  2. обойти проблему, используя синтаксис v-bind:
<input
  :id = "optionKey.toString()"
  v-model = "selection"
  class = "filter-options-input visually-hidden"
  v-bind = "{ value: optionKey, name, type }"
/>
  1. Игнорируйте его с помощью шаблона ignore:
<input
  ...
  v-model = "selection"
  ...
  :data-foo = "/* ts-ignore */"
  :value = "optionKey"
  ...
/>

Спасибо @tao за ваш ответ. Вы правы, окончательный код в браузере действительно работает. Здесь просто TypeScript не устраивает, и я не понимаю, почему. Но нет ли лучшего способа, чем просто игнорировать его или создать отдельный шаблон?

Hermann Dettmann 15.02.2023 09:53

Ах, спасибо за объяснение @tao! В этом есть смысл. Так что я должен каким-то образом сказать TypeScript, что это может быть только type = "radio" или type = "checkbox", но ничего больше, верно?

Hermann Dettmann 15.02.2023 11:15

Да, это должно убрать ошибку. Какое точное правило вызывает ошибку? Вы увидите это при наведении на ошибку.

tao 15.02.2023 12:04

Это сообщение об ошибке: литерал объекта не может иметь несколько свойств с одинаковым именем. ц(1117)

Hermann Dettmann 15.02.2023 12:24

(свойство) InputHTMLAttributes.value?: любое

Hermann Dettmann 15.02.2023 13:05

Не могли бы вы создать codeandbox.io (или аналогичный)? Он должен иметь как минимум package.json и компонент, где вы это видите. + минимум для воспроизведения проблемы.

tao 15.02.2023 13:49

Вот репродукция в Codesandbox: codeandbox.io/p/sandbox/…

Hermann Dettmann 15.02.2023 22:32

Привет @tao, большое спасибо за ваши усилия, подачу заявки и обновление вашего ответа с доступными исправлениями! Ваше объяснение действительно помогает лучше понять, в чем проблема. Отличная работа! Я нашел решение v-bind самым «элегантным» на данный момент. По какой-то странной причине это работает, только если я перемещаю v-model после директивы v-bind. Наоборот, я бы получил ошибку в директиве v-model. Но, в конце концов, вы правы, я использую Volar в VSCode, и отключение этого на самом деле не вариант, но я зарегистрирую проблему с vuejs/language-tools, как предложил Дэниел.

Hermann Dettmann 16.02.2023 22:41

Сообщает о проблеме в языковых инструментах vue: github.com/vuejs/language-tools/issues/2399. Давайте посмотрим.

Hermann Dettmann 16.02.2023 23:02

Как оказалось проблема была не в коде, а в моей IDE. Расширение Volar, которое я использую, имеет неточное определение типа реквизита для v-model. Теперь это исправлено в vuejs/language-tools с версией 1.1.3 (2023/2/18).

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