SODA Engineering Blog
🤕

Vue2からVue3への移行時に気をつけたい!`v-model`と`input[type="number"]`の予期せぬ型変換

2024/10/08に公開

Vue3では、inputがtype="number"を持つ場合はnumber修飾子が自動で適用されます


ref: https://ja.vuejs.org/guide/essentials/forms.html#number

一方Vue2では、明示的に.numberを使用しない限りv-modelは文字列のまま扱われていました

そのため、Vue2からVue3への移行をする際に、実装によっては意図しない挙動になってしまうかもしれません

検証環境を用意し、何が起こっているかを確認する

今回はVue2, Vue3と環境を用意し、iframeを使って1つのHTMLで確認できるよう動かしてみました
https://aokiken.github.io/vue-v-model-input-type-number-testing/

どういったケースで困るか

例えば、0から始まる入力を扱うもの(電話番号など)は、丸められてしまうため、バリデーションによっては保存できないなどの不具合が発生してしまいそうですね

他にも、APIでstringを期待しているのにnumberで送られてしまい、リクエストが成功しないケースなどが考えられそうです

どう対応するか

今回はinput[type="number"]input[type="text"] に変更するという方法で対応をしました
場所によっては pattern="[0-9]*", inputmode="numeric"をつけます

eslintのルールを作成してこの組み合わせを非推奨にする

https://github.com/vuejs/eslint-plugin-vue の実装を参考に、カスタムルールを作成してみました

const utils = require("eslint-plugin-vue/lib/utils");

/** @type {import("eslint").Rule.RuleModule} */
module.exports = {
  meta: {
    type: "problem",
    fixable: null,
    schema: [],
    docs: {
      description: "disallow using v-model on <input type='number'>",
    },
    messages: {
      noVModelOnNumberInput:
        'v-model on <input type="number"> now implicitly applies the number modifier, which can lead to unexpected type conversions. Avoid using v-model and instead handle value changes explicitly.',
    },
  },
  create(context) {
    return utils.defineTemplateBodyVisitor(context, {
      "VAttribute[directive=true][key.name.name='model']"(node) {
        const element = node.parent.parent;
        if (
          element &&
          element.name === "input" &&
          utils.hasAttribute(element, "type", "number")
        ) {
          context.report({
            node,
            loc: node.loc,
            messageId: "noVModelOnNumberInput",
          });
        }
      },
    });
  },
};

これは、破壊的変更?

Vue3へアップデートすることによって既存のコードが壊れる可能性があり、それを修正しなければならないという点で、破壊的変更と言えそうです。
ですが、 https://v3-migration.vuejs.org/ に今回の事象のことは記載されていなかったため、Zennにまとめてみることにしました

すでにIssueは上がっている

ですが、長い事動いていないように見えます😢
https://github.com/vuejs/v3-migration-guide/issues/32

SODA Engineering Blog
SODA Engineering Blog

Discussion