Vize

型と script のルール

このページに、各ルールの目的・前提・設定と、省略のない悪い例・良い例をまとめています。変更箇所は行の色で示します。コードをコピーすると、ソースコード全体を取得できます。各例に現在の対応範囲も明記しています。

ルール 例 目的
script/component-options-name-casing 悪い · 良い コンポーネントの name オプションを PascalCase に揃えます。
script/custom-event-name-casing 悪い · 良い emit するカスタムイベント名を指定した形式に揃えます。
script/define-emits-declaration 悪い · 良い defineEmits を型による宣言形式に揃えます。
script/define-macros-order 悪い · 良い script setup のコンパイラーマクロを一定の順に宣言します。
script/define-props-declaration 悪い · 良い defineProps を型による宣言形式に揃えます。
script/define-props-destructuring 悪い · 良い defineProps の分割代入スタイルを指定した方針に揃えます。
script/no-arrow-functions-in-watch 悪い · 良い Options API の watch ハンドラーにアロー関数を使う箇所を検出します。
script/no-async-in-computed 悪い · 良い computed の getter で非同期関数を使う箇所を検出します。
script/no-boolean-default 悪い · 良い Boolean prop の冗長な default を検出します。
script/no-computed-properties-in-data 悪い · 良い 初期化前の data() で算出プロパティを読む箇所を検出します。
script/no-deep-destructure-in-props 悪い · 良い defineProps の深い分割代入を検出します。
script/no-deprecated-data-object-declaration 悪い · 良い Vue 3 で関数にすべき data オプションのオブジェクト指定を検出します。
script/no-deprecated-delete-set 悪い · 良い Vue 3 で削除された $set / $delete を検出します。
script/no-deprecated-destroyed-lifecycle 悪い · 良い Vue 2 の destroyed / beforeDestroy を検出し、Vue 3 のライフサイクルフックに置き換えます。
script/no-deprecated-dollar-listeners-api 悪い · 良い Vue 3 で $attrs に統合された $listeners を検出します。
script/no-deprecated-dollar-scopedslots-api 悪い · 良い Vue 3 で $slots に統合された $scopedSlots を検出します。
script/no-deprecated-events-api 悪い · 良い Vue 3 で削除された $on / $off / $once を検出します。
script/no-deprecated-model-definition 悪い · 良い Vue 3 で削除された model オプションを検出します。
script/no-deprecated-props-default-this 悪い · 良い prop の default / validator 内で使えなくなった this を検出します。
script/no-deprecated-vue-config-keycodes 悪い · 良い 削除された Vue.config.keyCodes を検出します。
script/no-dupe-keys 悪い · 良い Options API の props / data / computed などのキー重複を検出します。
script/no-duplicate-attr-inheritance 悪い · 良い fallthrough 属性を同じコンポーネントで二重に適用する箇所を検出します。
script/no-export-in-script-setup 悪い · 良い script setup 内の export 文を検出します。
script/no-expose-after-await 悪い · 良い await の後の expose() と defineExpose() を禁止します。
script/no-get-current-instance 悪い · 良い Vapor で null を返す getCurrentInstance() を検出します。
script/no-import-compiler-macros 悪い · 良い 自動的に使える Vue コンパイラーマクロの import を検出します。
script/no-internal-imports 悪い · 良い Vue 内部モジュールからの import を検出します。
script/no-lifecycle-after-await 悪い · 良い setup() 内で await の後にライフサイクルフックを登録することを禁止します。
script/no-multiple-slot-args 悪い · 良い scoped slot 関数に複数の引数を渡す箇所を検出します。
script/no-next-tick 悪い · 良い Vapor 向けコンポーネントの nextTick() 使用を検出します。
script/no-options-api 悪い · 良い Vapor で Options API を使用する箇所を検出します。
script/no-potential-component-option-typo 悪い · 良い Options API のオプション名の入力ミスを検出します。
script/no-reactive-destructure 悪い · 良い reactive オブジェクトを分割代入し、リアクティビティを失う箇所を検出します。
script/no-ref-as-operand 悪い · 良い ref を演算の値として使う際に .value を参照します。
script/no-required-prop-with-default 悪い · 良い required: true と default を同時に持つ prop を検出します。
script/no-reserved-identifiers 悪い · 良い Vue コンパイラーが予約した識別子の宣言を検出します。
script/no-reserved-keys 悪い · 良い Options API のキーに Vue の予約名を使う箇所を検出します。
script/no-reserved-props 悪い · 良い prop 宣言に Vue の予約名を使う箇所を検出します。
script/no-restricted-globals 悪い · 良い 設定で禁止した実行環境のグローバル参照を検出します。
script/no-restricted-members 悪い · 良い 設定で禁止した object.property へのアクセスを検出します。
script/no-side-effects-in-computed-properties 悪い · 良い Options API の computed getter 内の副作用を検出します。
script/no-top-level-ref-in-script 悪い · 良い 通常の script のトップレベルで、リクエスト間に共有される状態を作る箇所を検出します。
script/no-unstable-nested-components 悪い · 良い setup / render 内で毎回コンポーネントを定義する箇所を検出します。
script/no-unused-emit-declarations 悪い · 良い 宣言したまま emit していないイベントを検出します。
script/no-use-computed-property-like-method 悪い · 良い Options API の computed プロパティをメソッドとして呼ぶ箇所を検出します。
script/no-watch-after-await 悪い · 良い setup() 内で await の後に停止ハンドルを保持せずにウォッチャーを登録することを禁止します。
script/no-with-defaults 悪い · 良い Vue 3.5 以降の props 分割代入の既定値を勧めます。
script/one-component-per-file 悪い · 良い 1 ファイルにコンポーネント定義が複数あることを検出します。
script/order-in-components 悪い · 良い コンポーネントオプションのプロパティ順を既定の並びに揃えます。
script/prefer-computed 悪い · 良い 他の状態から導ける値を watcher で同期する代わりに computed で表現します。
script/prefer-define-options 悪い · 良い name / inheritAttrs だけの通常 script を defineOptions() にまとめます。
script/prefer-import-from-vue 悪い · 良い 内部パッケージではなく vue から import します。
script/prefer-ref-over-reactive 悪い · 良い 状態管理に reactive() より ref() を使う方針を適用します。
script/prefer-use-attrs 悪い · 良い setup の context.attrs を useAttrs() に置き換えます。
script/prefer-use-id 悪い · 良い 一意な ID の生成に Vue 3.5 の useId() を使います。
script/prefer-use-slots 悪い · 良い setup の context.slots を useSlots() に置き換えます。
script/prefer-use-template-ref 悪い · 良い テンプレート参照に Vue 3.5 の useTemplateRef() を使います。
script/require-default-prop 悪い · 良い 省略可能な、Boolean 以外の prop に default を用意します。
script/require-explicit-emits 悪い · 良い emit するイベントを defineEmits または emits に宣言します。
script/require-explicit-slots 悪い · 良い useSlots() で使う slot を defineSlots の型で宣言します。
script/require-function-return-type 悪い · 良い 関数に戻り値の型注釈を指定します。
script/require-prop-type-constructor 悪い · 良い prop の type に文字列ではなくコンストラクターを指定します。
script/require-prop-types 悪い · 良い 各 prop の型を宣言します。
script/require-render-return 悪い · 良い render 関数が値を返すことを必須にします。
script/require-slots-as-functions 悪い · 良い Vue 3 の $slots プロパティを関数として呼び出します。
script/require-symbol-provide 悪い · 良い provide / inject のキーに衝突しにくい Symbol を使います。
script/require-typed-object-prop 悪い · 良い Object / Array の prop に具体的な型を指定します。
script/require-typed-ref 悪い · 良い 引数なし、null、undefined で呼び出す ref() に型引数を指定します。
script/require-valid-default-prop 悪い · 良い prop の default を宣言した型に合う値にします。
script/return-in-computed-property 悪い · 良い computed の getter に値を返す return を用意します。
script/return-in-emits-validator 悪い · 良い Options API の emits validator に戻り値を用意します。
script/valid-define-emits 悪い · 良い defineEmits の重複や型と実行時引数の併用を検出します。
script/valid-define-options 悪い · 良い defineOptions の引数と使用回数を検査します。
script/valid-define-props 悪い · 良い defineProps の重複や型と実行時引数の併用を検出します。
script/valid-next-tick 悪い · 良い nextTick() の完了を await、then、またはコールバックで扱います。
type/no-floating-promises 悪い · 良い 処理しないまま放置された Promise を検出します。
type/no-reactivity-loss 悪い · 良い リアクティブな値を代入や呼び出しで取り出し、元の更新に追従しないスナップショットになる箇所を検出します。
type/no-unsafe-template-binding 悪い · 良い テンプレートで安全でない型の値を使用する箇所を検出します。
type/require-typed-emits 悪い · 良い defineEmits に型定義を指定します。
type/require-typed-props 悪い · 良い defineProps に型定義を指定します。
type/strict-boolean-expressions 悪い · 良い script とテンプレートの条件式で安全な真偽判定を使います。

全ルール · ルールのオプション · ESLint 移行対応表 · プロジェクトの検査 · 子への属性の継承

script/component-options-name-casing

コンポーネントの name オプションを PascalCase に揃えます。

悪い例 · 良い例

既定の重大度: error
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/component-options-name-casing": "error"
      }
    },
  },
});
vp run lint

悪い

コンポーネントの name: 'my-component' が kebab-case です。このルールは文字列リテラルのコンポーネント名に PascalCase を求めます。

<script lang="ts">
export default {
  name: 'my-component' // kebab-case
}
</script>

良い

MyComponent は大文字で始まり、英数字だけで構成されるため、名前の検査条件を満たします。

<script lang="ts">
export default {
  name: 'MyComponent'
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/custom-event-name-casing

emit するカスタムイベント名を指定した形式に揃えます。

悪い例 · 良い例

既定の重大度: error
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: 型付きオプションと既定値を参照してください。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/custom-event-name-casing": "error"
      }
    },
  },
});
vp run lint

悪い

emit する文字列 my-event にハイフンが含まれ、既定の camelCase イベント命名規則に違反しています。

<script setup lang="ts">
const emit = defineEmits(['my-event'])
emit('my-event')         // kebab-case → report
</script>

良い

宣言と呼び出しの両方を myEvent にそろえ、イベント名の一致を保ったまま既定の命名規則を満たします。kebab-case に設定した場合の期待値は異なります。

<script setup lang="ts">
const emit = defineEmits(['myEvent'])
emit('myEvent')
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/define-emits-declaration

defineEmits を型による宣言形式に揃えます。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/define-emits-declaration": "warn"
      }
    },
  },
});
vp run lint

悪い

defineEmits(["change"]) は実行時の配列による宣言です。このスタイルルールは型ベースの宣言を推奨します。

<script setup lang="ts">
const emit = defineEmits(["change"]);
emit("change", 1);
</script>

良い

defineEmits<{ change: [id: number] }>() で宣言を型引数へ移し、emit("change", 1) が渡す数値のペイロードも明示します。

<script setup lang="ts">
const emit = defineEmits<{ change: [id: number] }>();
emit("change", 1);
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/define-macros-order

script setup のコンパイラーマクロを一定の順に宣言します。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: 型付きオプションと既定値を参照してください。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/define-macros-order": "warn"
      }
    },
  },
});
vp run lint

悪い

defineEmits が defineProps より先にありますが、<script setup> の先頭は defineProps、次に defineEmits でなければなりません。

<script setup lang="ts">
// defineEmits before defineProps
const emit = defineEmits<{ change: [value: string] }>()
const props = defineProps<{ count: number }>()
</script>

良い

import の直後、他のすべての文より前に defineProps、defineEmits の順で置きます。その他のマクロの順序は自由です。

<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps<{ count: number }>()
const emit = defineEmits<{ change: [value: string] }>()
const model = defineModel<string>()
const value = ref(0)
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/define-props-declaration

defineProps を型による宣言形式に揃えます。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/define-props-declaration": "warn"
      }
    },
  },
});
vp run lint

悪い

defineProps({ title: String }) は実行時オブジェクトを渡しており、このルールが推奨する型ベースの props 宣言と異なります。

<script setup lang="ts">
const props = defineProps({ title: String });
console.log(props.title);
</script>

良い

defineProps<{ title: string }>() の型引数で title を宣言し、実行時の宣言引数を使わずに props.title の参照を保ちます。

<script setup lang="ts">
const props = defineProps<{ title: string }>();
console.log(props.title);
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/define-props-destructuring

defineProps の分割代入スタイルを指定した方針に揃えます。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: 型付きオプションと既定値を参照してください。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/define-props-destructuring": "warn"
      }
    },
  },
});
vp run lint

悪い

defineProps の結果を分割代入せず、単一の props 変数に代入しており、既定の分割代入の推奨に従っていません。

<script setup lang="ts">
const props = defineProps<{ foo: string }>()
</script>

良い

オブジェクトパターンで foo と bar を直接取り出し、省略可能な bar に既定値を付けます。Vue 3.5 以降のリアクティブな props 分割代入を前提とし、設定を never にした場合は逆の形式を推奨します。

<script setup lang="ts">
const { foo, bar = 'default' } = defineProps<{ foo: string; bar?: string }>()
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-arrow-functions-in-watch

Options API の watch ハンドラーにアロー関数を使う箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-arrow-functions-in-watch": "error"
      }
    },
  },
});
vp run lint

悪い

Options API の watcher value と other.handler がアロー関数です。アロー関数の this は外側から引き継がれ、コンポーネントインスタンスとして束縛されません。

<script lang="ts">
export default {
  watch: {
    // `this` is not the component instance inside an arrow function.
    value: () => {
      this.doSomething()
    },
    other: {
      handler: () => {}
    }
  }
}
</script>

良い

両ハンドラーを通常のメソッドに変え、Vue が this をコンポーネントインスタンスに束縛できるようにします。オブジェクト形式では deep: true オプションも指定できます。

<script lang="ts">
export default {
  watch: {
    value(newValue, oldValue) {
      this.doSomething()
    },
    other: {
      handler(newValue) {},
      deep: true
    }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-async-in-computed

computed の getter で非同期関数を使う箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-async-in-computed": "error"
      }
    },
  },
});
vp run lint

悪い

computed の getter が async であり、fetch の結果を同期的な計算値ではなく Promise として返します。

<script setup lang="ts">
import { computed } from "vue";
const data = computed(async () => {
  const response = await fetch("/api/data");
  return response.json();
});
</script>

良い

非同期の fetch を watch に移し、結果を data.value に保存します。クリーンアップで古い要求を中止し、無効になったコールバックが古い結果を書き込むのを防ぎます。async な computed getter は残りません。

<script setup lang="ts">
import { ref, watch } from "vue";
const query = ref("");
const data = ref<unknown>(null);
watch(query, async (value, _oldValue, onCleanup) => {
  const controller = new AbortController();
  let active = true;
  onCleanup(() => { active = false; controller.abort(); });
  const response = await fetch(`/api/data?q=${encodeURIComponent(value)}`, { signal: controller.signal });
  const next: unknown = await response.json();
  if (active) data.value = next;
});
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-boolean-default

Boolean prop の冗長な default を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-boolean-default": "warn"
      }
    },
  },
});
vp run lint

悪い

disabled と checked は、型に Boolean コンストラクターだけを指定した prop に default を付けています。明示的な false もこのルールの対象です。

<script lang="ts">
export default {
  props: {
    // Boolean props already default to false; an explicit default is confusing.
    disabled: { type: Boolean, default: true },
    checked: { type: Boolean, default: false }
  }
}
</script>

良い

Boolean のみの props では default を省き、Vue の暗黙の false を使います。[Boolean, String] の共用型と Number の prop は、この検査が単独の Boolean コンストラクターに限られることを示します。

<script lang="ts">
export default {
  props: {
    // No explicit default: defaults to false.
    disabled: { type: Boolean },
    disabled2: Boolean,
    // Union type may legitimately need a default.
    value: { type: [Boolean, String], default: '' },
    // Non-Boolean prop.
    count: { type: Number, default: 0 }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-computed-properties-in-data

初期化前の data() で算出プロパティを読む箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-computed-properties-in-data": "error"
      }
    },
  },
});
vp run lint

悪い

data() が算出プロパティ doubled を this.doubled として返しています。算出プロパティはまだ初期化されていません。

<script lang="ts">
export default {
  data() {
    return { value: this.doubled }
  },
  computed: {
    doubled() { return 1 }
  }
}
</script>

良い

data() はただの value を返し、doubled は初期化後に this.value を読みます。

<script lang="ts">
export default {
  data() {
    return { value: 1 }
  },
  computed: {
    doubled() { return this.value * 2 }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deep-destructure-in-props

defineProps の深い分割代入を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deep-destructure-in-props": "warn"
      }
    },
  },
});
vp run lint

悪い

この SFC 内に一つだけある、内容を直接記述した <script setup> のトップレベルで、コンパイラーマクロの props の user からさらに name を取り出し、既定の深さ 1 を超えています。オブジェクトの内側の配列も深さに数えます。Opinionated と Nuxt では、深さの方針を検査するこの警告が既定で有効です。他のプリセットでは個別に有効化します。コンパイラーの propsDestructure 設定は参照せず、withDefaults でコンパイルできる場合も警告します。

<script setup lang="ts">
const { user: { name } } = defineProps<{ user: { name: string } }>();
</script>

良い

props オブジェクトを保ち、computed の getter で props.user.name を参照します。深い代入パターンを使わず、入れ子の参照を明示します。

<script setup lang="ts">
import { computed } from "vue";
const props = defineProps<{ user: { name: string } }>();
const userName = computed(() => props.user.name);
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-data-object-declaration

Vue 3 で関数にすべき data オプションのオブジェクト指定を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-data-object-declaration": "error"
      }
    },
  },
});
vp run lint

悪い

Options API の data がオブジェクトリテラルであり、Vue 3 では受け付けない Vue 2 の形式です。

<script lang="ts">
export default {
  // `data` must be a function in Vue 3, not an object literal.
  data: {
    count: 0
  }
}
</script>

良い

data() が新しい { count: 0 } を返すようにし、Vue 3 が求める関数形式のデータ宣言にします。

<script lang="ts">
export default {
  data() {
    return { count: 0 }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-delete-set

Vue 3 で削除された $set / $delete を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-delete-set": "error"
      }
    },
  },
});
vp run lint

悪い

created() が削除された this.$set で ready を追加しています。

<script lang="ts">
export default {
  created() {
    this.$set(this.item, 'ready', true)
  }
}
</script>

良い

同じフィールドを this.item.ready = true で直接代入します。

<script lang="ts">
export default {
  created() {
    this.item.ready = true
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-destroyed-lifecycle

Vue 2 の destroyed / beforeDestroy を検出し、Vue 3 のライフサイクルフックに置き換えます。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: 対応している診断で利用できます
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-destroyed-lifecycle": "error"
      }
    },
  },
});
vp run lint

悪い

タイマーの後片付けに、Vue 3 で削除された Vue 2 のライフサイクルオプション beforeDestroy を使っています。

<script lang="ts">
export default { beforeDestroy() { clearTimeout(this.timer); } };
</script>

良い

タイマーの後片付けの処理をそのまま残し、フック名を Vue 3 の beforeUnmount に変更します。

<script lang="ts">
export default { beforeUnmount() { clearTimeout(this.timer); } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-dollar-listeners-api

Vue 3 で $attrs に統合された $listeners を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-dollar-listeners-api": "error"
      }
    },
  },
});
vp run lint

悪い

スクリプトが削除済みの $listeners を参照しています。テンプレートでもコンポーネントの $listeners を転送しています。所有元を確認できた同名の setup 変数やテンプレートローカル変数は別の値として扱います。

<script>
export default {
  mounted() {
    const vm = this
    return vm.$listeners
  }
}
</script>
<template><Child v-on="$listeners" /></template>

良い

this.$attrs と v-bind="$attrs" で Vue 3 の属性とリスナーを参照・転送します。スクリプト内の参照元のオブジェクトや参照方法に対する、既存の広い検出範囲は変わりません。

<script>
export default {
  mounted() {
    return this.$attrs
  }
}
</script>
<template><Child v-bind="$attrs" /></template>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-dollar-scopedslots-api

Vue 3 で $slots に統合された $scopedSlots を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-dollar-scopedslots-api": "error"
      }
    },
  },
});
vp run lint

悪い

this.$scopedSlots、ctx.$scopedSlots、this や ctx を付けずに参照した $scopedSlots が、Vue 3 で削除された Vue 2 のスコープ付きスロット API を使っています。

<script setup lang="ts">
const header = this.$scopedSlots.header
const footer = ctx.$scopedSlots.footer
render($scopedSlots.default)
</script>

良い

$scopedSlots を $slots に置き換え、統合された slot API を使います。この例は削除された API 名の置換を示すもので、参照元の setup コンテキストを作る例ではありません。

<script setup lang="ts">
const header = this.$slots.header
const footer = ctx.$slots.footer
render($slots.default)
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-events-api

Vue 3 で削除された $on / $off / $once を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-events-api": "error"
      }
    },
  },
});
vp run lint

悪い

$on、$once、$off の呼び出しが、Vue 3 で削除されたインスタンスのイベントバスメソッドを使っています。

<script>
export default {
  mounted() {
    this.$on('event', handler)
    const vm = this
    vm.$once('event', handler)
    this.$off('event', handler)
  }
}
</script>

良い

有効な $emit は維持し、イベントバスへの購読は外部 emitter の on に移します。親へのイベント送信と外部イベントバスを別々の API で表します。

<script>
import mitt from 'mitt'
const emitter = mitt()
export default {
  mounted() {
    this.$emit('event', payload)
    emitter.on('event', handler)
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-model-definition

Vue 3 で削除された model オプションを検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-model-definition": "error"
      }
    },
  },
});
vp run lint

悪い

コンポーネントが Vue 2 の model オプションを prop と event 付きで宣言しています。

<script lang="ts">
export default {
  model: {
    prop: 'value',
    event: 'input'
  }
}
</script>

良い

modelValue prop と update:modelValue イベントを宣言します。

<script lang="ts">
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-props-default-this

prop の default / validator 内で使えなくなった this を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-props-default-this": "error"
      }
    },
  },
});
vp run lint

悪い

prop の既定値関数とバリデーターが this を参照していますが、Vue 3 ではこれらの関数の this からコンポーネントインスタンスを参照できません。

<script lang="ts">
export default {
  props: {
    size: {
      type: Number,
      // `this` is not the component instance in Vue 3.
      default() {
        return this.defaultSize
      }
    },
    value: {
      type: Number,
      validator() {
        return this.value > 0
      }
    }
  }
}
</script>

良い

既定値関数は引数の props.baseSize を使い、validator は引数の value を検査します。どちらも利用できないインスタンスの this に依存しなくなります。

<script lang="ts">
export default {
  props: {
    size: {
      type: Number,
      // Vue 3 passes the raw props as the first argument instead.
      default(props) {
        return props.baseSize
      }
    },
    value: {
      type: Number,
      validator(value) {
        return value > 0
      }
    }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-deprecated-vue-config-keycodes

削除された Vue.config.keyCodes を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-deprecated-vue-config-keycodes": "error"
      }
    },
  },
});
vp run lint

悪い

削除された Vue.config.keyCodes.enter にキーコードを代入しています。

<script setup lang="ts">
Vue.config.keyCodes.enter = 13
</script>

良い

キーコードは通常の定数 const enter = 13 にします。

<script setup lang="ts">
const enter = 13
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-dupe-keys

Options API の props / data / computed などのキー重複を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-dupe-keys": "error"
      }
    },
  },
});
vp run lint

悪い

foo が props と data の両方に、bar が computed と methods の両方に宣言され、コンポーネントインスタンス上で同じキーの宣言が衝突しています。

<script lang="ts">
export default {
  props: ['foo'],
  data() {
    return { foo: 1 } // duplicate of prop `foo`
  },
  computed: {
    bar() { return 2 }
  },
  methods: {
    bar() {} // duplicate of computed `bar`
  }
}
</script>

良い

prop、data、computed に別々の名前 foo、bar、baz を使い、オプション間の重複を取り除きます。

<script lang="ts">
export default {
  props: ['foo'],
  data() {
    return { bar: 1 }
  },
  computed: {
    baz() { return 2 }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-duplicate-attr-inheritance

fallthrough 属性を同じコンポーネントで二重に適用する箇所を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-duplicate-attr-inheritance": "warn"
      }
    },
  },
});
vp run lint

悪い

自動の属性継承を有効にしたまま、ボタンにも $attrs を転送しています。同じ属性が二重に適用される可能性があります。

<script setup></script>
<template><div><button v-bind="$attrs">Save</button></div></template>

良い

inheritAttrs: false で自動の継承を無効にし、ボタンへの明示的な転送だけを残します。

<script setup>defineOptions({ inheritAttrs: false })</script>
<template><div><button v-bind="$attrs">Save</button></div></template>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-export-in-script-setup

script setup 内の export 文を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-export-in-script-setup": "error"
      }
    },
  },
});
vp run lint

悪い

export const count が <script setup> からモジュールの値をエクスポートしようとしています。このブロックでは実行時の export は禁止されています。

<script setup lang="ts">
export const count = 1;
</script>

良い

export を取り除き、count をモジュールの export ではなく setup の変数にします。

<script setup lang="ts">
const count = 1;
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-expose-after-await

await の後の expose() と defineExpose() を禁止します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-expose-after-await": "error"
      }
    },
  },
});
vp run lint

悪い

トップレベルの await の後に defineExpose() を呼んでいます。この時点ではコンポーネントのインスタンスが確定していないため、何も公開されません。

<script setup lang="ts">
await loadData()
defineExpose({ reload })
</script>

良い

最初の await より前、インスタンスが確定している間に defineExpose() を呼びます。

<script setup lang="ts">
defineExpose({ reload })
await loadData()
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-get-current-instance

Vapor で null を返す getCurrentInstance() を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vapor を想定した script 検査。明示的に有効にすると通常の script でも同じ禁止を適用します。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-get-current-instance": "error"
      }
    },
  },
});
vp run lint

悪い

Vapor を指定した setup が getCurrentInstance をインポートして呼び出し、Vapor 向けコンポーネントでこのルールが禁止するインスタンス API に依存しています。

<script setup lang="ts" vapor>
import { getCurrentInstance } from "vue";
const instance = getCurrentInstance();
</script>

良い

inject("app-config") で明示的に提供された設定を受け取り、getCurrentInstance のインポートも呼び出しも使いません。

<script setup lang="ts" vapor>
import { inject } from "vue";
const appConfig = inject("app-config");
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-import-compiler-macros

自動的に使える Vue コンパイラーマクロの import を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-import-compiler-macros": "error"
      }
    },
  },
});
vp run lint

悪い

vue から defineProps と defineEmits をインポートしていますが、これらは <script setup> で直接使えるコンパイラーマクロです。

<script setup lang="ts">
import { defineProps, defineEmits } from "vue";
const props = defineProps<{ title: string }>();
const emit = defineEmits<{ save: [id: number] }>();
</script>

良い

マクロのインポートを除き、型付きのマクロ呼び出しは保ちます。これらの宣言に実行時のインポートは不要です。

<script setup lang="ts">
const props = defineProps<{ title: string }>();
const emit = defineEmits<{ save: [id: number] }>();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-internal-imports

Vue 内部モジュールからの import を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-internal-imports": "error"
      }
    },
  },
});
vp run lint

悪い

両方の import が Vue の公開エントリーポイントではなく内部の dist ファイルを参照し、コンポーネントをビルド成果物のパスに依存させています。

<script setup lang="ts">
import { foo } from '@vue/runtime-core/dist/runtime-core.esm-bundler'
import { bar } from 'vue/dist/vue.esm-bundler'
</script>

良い

必要なヘルパーを vue からインポートし、内部の配布ファイルの配置への依存を取り除きます。

<script setup lang="ts">
import { ref, computed } from 'vue'
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-lifecycle-after-await

setup() 内で await の後にライフサイクルフックを登録することを禁止します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-lifecycle-after-await": "error"
      }
    },
  },
});
vp run lint

悪い

setup() で await loadData() の後に onMounted() を呼んでいます。この時点ではコンポーネントのインスタンスがないため、フックは登録されません。

<script lang="ts">
import { onMounted } from 'vue'
export default {
  async setup() {
    await loadData()
    onMounted(() => {})
  },
}
</script>

良い

最初の await より前、setup() が同期的に実行されている間に onMounted() を登録します。

<script lang="ts">
import { onMounted } from 'vue'
export default {
  async setup() {
    onMounted(() => {})
    await loadData()
  },
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-multiple-slot-args

scoped slot 関数に複数の引数を渡す箇所を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-multiple-slot-args": "warn"
      }
    },
  },
});
vp run lint

悪い

スロットの呼び出しで、複数の位置引数や、個数不明の引数をスプレッド構文で渡しています。Vue のスロットは位置引数の列ではなく、一つの props オブジェクトを受け取ります。

<script setup lang="ts">
slots.default(foo, bar)
$slots.header(a, b)
this.$scopedSlots.item(x, y)
useSlots().default(a, b)
slots.default(...args)
</script>

良い

{ foo, bar } でデータを一つの引数にまとめます。slotProps を渡す呼び出しと引数を省いた呼び出しも、このルールが許可するスロットの呼び出し方です。

<script setup lang="ts">
slots.default({ foo, bar })
slots.default(slotProps)
slots.default()
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-next-tick

Vapor 向けコンポーネントの nextTick() 使用を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vapor を想定した script 検査。明示的に有効にすると通常の script でも同じ禁止を適用します。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-next-tick": "error"
      }
    },
  },
});
vp run lint

悪い

Vapor 向けコンポーネントが nextTick をインポートして await し、この移行ルールが拒否する DOM 更新待ちの依存を作っています。

<script setup lang="ts" vapor>
import { nextTick } from "vue";
await nextTick();
</script>

良い

useTemplateRef で input を取得し、onMounted でフォーカスします。例の nextTick への依存を、明示的なマウント時の処理に置き換えます。

<script setup lang="ts" vapor>
import { onMounted, useTemplateRef } from "vue";
const input = useTemplateRef<HTMLInputElement>("input");
onMounted(() => { input.value?.focus(); });
</script>
<template><input ref="input"></template>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-options-api

Vapor で Options API を使用する箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vapor を想定した script 検査。明示的に有効にすると通常の script でも同じ禁止を適用します。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-options-api": "error"
      }
    },
  },
});
vp run lint

悪い

default export のオブジェクトに Options API の data() を宣言しており、このルールが禁止するコンポーネントオプションの形式です。

<script lang="ts">
export default {
  data() {
    return { count: 0 };
  },
};
</script>

良い

状態を Vapor の <script setup> 内の Composition API ref に移し、Options API のオブジェクトと data オプションを取り除きます。

<script setup lang="ts" vapor>
const count = ref(0);
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-potential-component-option-typo

Options API のオプション名の入力ミスを検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-potential-component-option-typo": "error"
      }
    },
  },
});
vp run lint

悪い

オプション名が既知の methods から一文字欠けた method になり、意図したメソッド宣言として扱われません。

<script lang="ts">
export default { method: { save() {} } };
</script>

良い

キーを methods に修正し、save() を既知のコンポーネントオプション内に置きます。

<script lang="ts">
export default { methods: { save() {} } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-reactive-destructure

reactive オブジェクトを分割代入し、リアクティビティを失う箇所を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-reactive-destructure": "warn"
      }
    },
  },
});
vp run lint

悪い

const { count, name } = state が reactive オブジェクトからプリミティブ値をコピーし、その後のプロパティ更新とのつながりを失います。

<script setup lang="ts">
import { reactive } from "vue";
const state = reactive({ count: 0, name: "Ada" });
const { count, name } = state;
</script>

良い

toRefs(state) を分割代入して count と name の ref を作り、それぞれを元のリアクティブなプロパティにつなげます。

<script setup lang="ts">
import { reactive, toRefs } from "vue";
const state = reactive({ count: 0, name: "Ada" });
const { count, name } = toRefs(state);
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-ref-as-operand

ref を演算の値として使う際に .value を参照します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-ref-as-operand": "error"
      }
    },
  },
});
vp run lint

悪い

count + 1 は ref が包む数値ではなく、ref オブジェクトそのものを算術演算の対象にしています。

<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
const next = count + 1;
</script>

良い

count.value + 1 で内側の数値を取り出してから加算します。script の演算では ref の値を明示的に参照します。

<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
const next = count.value + 1;
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-required-prop-with-default

required: true と default を同時に持つ prop を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-required-prop-with-default": "error"
      }
    },
  },
});
vp run lint

悪い

title に必須指定と "Untitled" の既定値を同時に付け、必須の入力という契約と未指定時の代替値を併記しています。

<script lang="ts">
export default { props: { title: { type: String, required: true, default: "Untitled" } } };
</script>

良い

required: true を除いて title を任意入力にし、"Untitled" を未指定時の既定値として残します。

<script lang="ts">
export default { props: { title: { type: String, default: "Untitled" } } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-reserved-identifiers

Vue コンパイラーが予約した識別子の宣言を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-reserved-identifiers": "error"
      }
    },
  },
});
vp run lint

悪い

変数名 __props、__emit、__sfc__ が Vue コンパイラーの生成コード用に予約された識別子と重なっています。

<script setup lang="ts">
const __props = { name: "Ada" };
const __emit = () => {};
const __sfc__ = {};
</script>

良い

通常の名前 props、emit、componentData を使い、props と emits の宣言を保ったまま生成用識別子との重複を避けます。

<script setup lang="ts">
const props = defineProps<{ name: string }>();
const emit = defineEmits<{ save: [] }>();
const componentData = {};
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-reserved-keys

Options API のキーに Vue の予約名を使う箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-reserved-keys": "error"
      }
    },
  },
});
vp run lint

悪い

data の $el が Vue 組み込みのインスタンスプロパティと重なり、予約された $ 接頭辞も使っています。

<script lang="ts">
export default { data() { return { $el: "custom" }; } };
</script>

良い

アプリケーションのデータ名を elementLabel に変え、組み込みのインスタンス API と予約接頭辞を避けます。

<script lang="ts">
export default { data() { return { elementLabel: "custom" }; } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-reserved-props

prop 宣言に Vue の予約名を使う箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-reserved-props": "error"
      }
    },
  },
});
vp run lint

悪い

オブジェクト形式の ref と $foo、配列形式の key は予約された prop 名です。ref と key はフレームワーク用であり、$ で始まる名前も拒否されます。

<script lang="ts">
export default {
  props: {
    ref: String,   // reserved
    $foo: Number    // `$`-prefixed names are reserved
  }
}

export default {
  props: ['key']    // reserved (array form)
}
</script>

良い

通常の prop 名 name と refValue に変え、予約された名前と接頭辞を避けます。

<script lang="ts">
export default {
  props: {
    name: String,
    refValue: Number
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-restricted-globals

設定で禁止した実行環境のグローバル参照を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: 型付きオプションと既定値を参照してください。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-restricted-globals": "error"
      }
    },
  },
});
vp run lint

悪い

既定で制限されるグローバル process、localStorage、sessionStorage を直接参照し、設定やストレージ用の明示的なヘルパーを通していません。

<script setup lang="ts">
const flag = process.env.FEATURE_FLAG
const token = localStorage.getItem('auth.token')
sessionStorage.setItem('view.scroll', String(window.scrollY))
</script>

良い

useFeatureFlag、authStorage.read、viewStorage.write に移し、制限対象のグローバルの直接参照を除きます。残る window.scrollY はこのルールの既定の制限対象ではなく、SSR の安全性は別途確認が必要です。

<script setup lang="ts">
// Use a typed config helper that distinguishes server vs. client.
const flag = useFeatureFlag('FEATURE_FLAG')

// Use a typed wrapper that scopes keys and handles SSR / disabled storage.
const token = authStorage.read('auth.token')
viewStorage.write('view.scroll', String(window.scrollY))
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-restricted-members

設定で禁止した object.property へのアクセスを検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: 型付きオプションと既定値を参照してください。

この例では window.localStorage を禁止しています。既定の禁止リストはなく、有効にするだけでは検出されません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-restricted-members": "error"
      },
      "ruleOptions": {
        "script/no-restricted-members": {
          "members": [
            {
              "object": "window",
              "property": "localStorage"
            }
          ]
        }
      }
    },
  },
});
vp run lint

悪い

ruleOptions に { object: "window", property: "localStorage" } を設定した場合、window.localStorage は禁止されたオブジェクトとメンバーの組み合わせです。このルールに既定の禁止メンバーはありません。

<script setup lang="ts">
const token = window.localStorage.getItem("token");
</script>

良い

authStorage.read("token") でアプリケーションのストレージヘルパーに処理を任せ、設定で禁止した window.localStorage を参照しなくなります。

<script setup lang="ts">
const token = authStorage.read("token");
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-side-effects-in-computed-properties

Options API の computed getter 内の副作用を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-side-effects-in-computed-properties": "error"
      }
    },
  },
});
vp run lint

悪い

doubled が this.count に代入し、reversed が reverse() で this.items を変更しています。どちらのゲッターも、値を計算する元の状態を変更してしまっています。

<script lang="ts">
export default {
  data() {
    return { count: 0, items: [] }
  },
  computed: {
    doubled() {
      this.count = this.count * 2 // side effect: assigns to data
      return this.count
    },
    reversed() {
      return this.items.reverse() // side effect: mutates the array
    }
  }
}
</script>

良い

doubled は代入せず乗算結果を返します。reversed は配列をコピーしてから反転し、getter が元のコンポーネント状態を変更しないようにします。

<script lang="ts">
export default {
  data() {
    return { count: 0, items: [] }
  },
  computed: {
    doubled() {
      return this.count * 2
    },
    reversed() {
      return [...this.items].reverse() // operate on a copy
    }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-top-level-ref-in-script

通常の script のトップレベルで、リクエスト間に共有される状態を作る箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-top-level-ref-in-script": "error"
      }
    },
  },
});
vp run lint

悪い

通常の <script> がモジュール直下で count と user を初期化しています。SSR では、この状態がコンポーネントインスタンスやリクエスト間で共有され得ます。

<script>
// This state is shared across all requests in SSR!
const count = ref(0)
const user = reactive({ name: '' })

export default {
  setup() {
    return { count, user }
  }
}
</script>

良い

script setup の ref はコンポーネントごとに初期化されます。通常の script には定数、状態を作る関数、setup() 内で作る ref を置き、モジュール直下でリアクティブな状態を作りません。

<script setup>
// Script setup creates fresh state per request
const count = ref(0)
</script>

<script>
// Constants are fine
const API_URL = 'https://api.example.com'

// Functions that create state are fine
function createState() {
  return reactive({ count: 0 })
}

export default {
  setup() {
    // Create state inside setup
    const count = ref(0)
    return { count }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-unstable-nested-components

setup / render 内で毎回コンポーネントを定義する箇所を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-unstable-nested-components": "warn"
      }
    },
  },
});
vp run lint

悪い

親の setup() 内で defineComponent を呼び、setup が実行されるたびに新しい Child のコンポーネント定義を作っています。

<script lang="ts">
import { defineComponent } from "vue";
export default { setup() { const Child = defineComponent({ render() { return null; } }); return { Child }; } };
</script>

良い

Child の定義をモジュール直下に移し、setup() は作り直さず既存の定義を返すようにします。

<script lang="ts">
import { defineComponent } from "vue";
const Child = defineComponent({ render() { return null; } });
export default { setup() { return { Child }; } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-unused-emit-declarations

宣言したまま emit していないイベントを検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-unused-emit-declarations": "warn"
      }
    },
  },
});
vp run lint

悪い

defineEmits は change と unused を宣言していますが、受け取った emit 関数が送信する文字列イベントは change だけです。

<script setup lang="ts">
const emit = defineEmits(['change', 'unused'])
emit('change')
// `unused` is never emitted
</script>

良い

unused を除き、イベント宣言を実際の送信にそろえます。この例では emit の参照を外部へ渡していないため、ローカルの使用状況から判断できます。

<script setup lang="ts">
const emit = defineEmits(['change'])
emit('change')
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-use-computed-property-like-method

Options API の computed プロパティをメソッドとして呼ぶ箇所を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-use-computed-property-like-method": "error"
      }
    },
  },
});
vp run lint

悪い

this.total() は computed getter の公開する値を関数として呼び出しています。この getter が返す 3 は呼び出せません。

<script lang="ts">
export default { computed: { total() { return 3; } }, methods: { log() { console.log(this.total()); } } };
</script>

良い

呼び出しの括弧を除いて this.total とし、log から計算済みの数値を参照します。

<script lang="ts">
export default { computed: { total() { return 3; } }, methods: { log() { console.log(this.total); } } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-watch-after-await

setup() 内で await の後に停止ハンドルを保持せずにウォッチャーを登録することを禁止します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-watch-after-await": "error"
      }
    },
  },
});
vp run lint

悪い

await loadData() の後に watch() を作成し、停止ハンドルも捨てています。このウォッチャーはコンポーネントと一緒に停止されません。

<script lang="ts">
import { watch } from 'vue'
export default {
  async setup(props) {
    await loadData()
    watch(() => props.id, reload)
  },
}
</script>

良い

最初の await より前にウォッチャーを作成するため、コンポーネントのアンマウント時に Vue が停止します。

<script lang="ts">
import { watch } from 'vue'
export default {
  async setup(props) {
    watch(() => props.id, reload)
    await loadData()
  },
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/no-with-defaults

Vue 3.5 以降の props 分割代入の既定値を勧めます。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/no-with-defaults": "warn"
      }
    },
  },
});
vp run lint

悪い

型付きの props 宣言を withDefaults で包んで count と name の既定値を指定しており、ここで推奨する Vue 3.5 以降の分割代入の既定値を使っていません。

<script setup lang="ts">
const props = withDefaults(defineProps<{ count?: number; name?: string }>(), { count: 0, name: "Ada" });
</script>

良い

分割代入の変数に count = 0 と name = "Ada" を直接指定し、withDefaults のラッパーを取り除きます。

<script setup lang="ts">
const { count = 0, name = "Ada" } = defineProps<{ count?: number; name?: string }>();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/one-component-per-file

1 ファイルにコンポーネント定義が複数あることを検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/one-component-per-file": "warn"
      }
    },
  },
});
vp run lint

悪い

ファイルが Parent を export し、components の中にもう一つの Child を定義しています。

<script lang="ts">
export default {
  name: 'Parent',
  components: {
    Child: { name: 'Child' }
  }
}
</script>

良い

ファイルが定義するのは Parent だけです。

<script lang="ts">
export default {
  name: 'Parent'
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/order-in-components

コンポーネントオプションのプロパティ順を既定の並びに揃えます。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/order-in-components": "warn"
      }
    },
  },
});
vp run lint

悪い

data が props より前に書かれており、後ろのグループが前のグループより上にあります。

<script lang="ts">
export default {
  data() {
    return { count: 0 }
  },
  props: ['label']
}
</script>

良い

props が data より前にあり、既定のグループ順と一致します。

<script lang="ts">
export default {
  props: ['label'],
  data() {
    return { count: 0 }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-computed

他の状態から導ける値を watcher で同期する代わりに computed で表現します。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

派生値だけを代入する watcher が対象です。ユーザーが編集するコピーや別の副作用を持つ処理は対象外です。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-computed": "warn"
      }
    },
  },
});
vp run lint

悪い

watcher が count から求めた値を別の ref doubled に書き込むだけであり、派生状態を手作業で同期しています。

<script setup lang="ts">
import { ref, watch } from "vue";
const count = ref(0);
const doubled = ref(0);
watch(count, (value) => { doubled.value = value * 2; });
</script>

良い

computed(() => count.value * 2) で導出を直接表し、書き込み可能な追加 ref と同期用 watcher を取り除きます。

<script setup lang="ts">
import { ref, computed } from "vue";
const count = ref(0);
const doubled = computed(() => count.value * 2);
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-define-options

name / inheritAttrs だけの通常 script を defineOptions() にまとめます。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-define-options": "warn"
      }
    },
  },
});
vp run lint

悪い

通常の script の処理が name と inheritAttrs だけを持つオブジェクトの export に限られ、defineOptions で表せるオプションだけを宣言しています。

<script lang="ts">
export default { name: 'MyComponent', inheritAttrs: false }
</script>

良い

data() が Options API の処理を含むため、オプションの宣言だけを持つ script を対象とする、このルールの提案の範囲外です。この良い例は、通常の script を残せる例外を示しています。悪い例を直接移行する場合は <script setup> 内で defineOptions({ name: 'MyComponent', inheritAttrs: false }) を使います。

<script lang="ts">
// Real options logic — keep the plain script.
export default {
  name: 'MyComponent',
  data() { return { count: 0 } },
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-import-from-vue

内部パッケージではなく vue から import します。

悪い例 · 良い例

既定の重大度: warning
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: 対応している診断で利用できます
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-import-from-vue": "warn"
      }
    },
  },
});
vp run lint

悪い

ref と h を公開パッケージ vue ではなく、内部の @vue/runtime-core と @vue/runtime-dom からインポートしています。

<script setup lang="ts">
import { ref } from '@vue/runtime-core'
import { h } from '@vue/runtime-dom'
</script>

良い

公開ヘルパーは vue からインポートします。vue が公開しない isString は @vue/shared を維持します。名前空間・デフォルト・公開と非公開の混在 import は警告のみで、自動修正しません。

<script setup lang="ts">
import { ref, h } from 'vue'
import { isString } from '@vue/shared'
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-ref-over-reactive

状態管理に reactive() より ref() を使う方針を適用します。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-ref-over-reactive": "warn"
      }
    },
  },
});
vp run lint

悪い

状態を reactive で作っており、ref を優先するこのルールの方針に合っていません。これはスタイルの推奨を示す例であり、reactive オブジェクト自体が不正という意味ではありません。

<script setup lang="ts">
// reactive requires careful handling to avoid losing reactivity
const state = reactive({
  count: 0,
  name: 'foo'
})
</script>

良い

スカラーとオブジェクトの状態をどちらも ref で作ります。関連するフィールドを個別の ref に分ける例も含め、推奨する状態の作成形式にそろえます。

<script setup lang="ts">
// ref is more explicit and safer
const count = ref(0)
const name = ref('foo')

// For objects, ref still works
const user = ref({ name: 'foo', age: 20 })

// Or use multiple refs for related data
const userName = ref('foo')
const userAge = ref(20)
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-use-attrs

setup の context.attrs を useAttrs() に置き換えます。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-use-attrs": "warn"
      }
    },
  },
});
vp run lint

悪い

setup がコンテキスト引数の分割代入で attrs を受け取っています。このルールは Composition API のヘルパーへの置換を求めます。

<script lang="ts">
export default { setup(_props, { attrs }) { console.log(attrs.class); } };
</script>

良い

setup 内で useAttrs() から attrs を取得し、第二引数に依存せず attrs.class の参照を保ちます。

<script lang="ts">
import { useAttrs } from "vue";
export default { setup() { const attrs = useAttrs(); console.log(attrs.class); } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-use-id

一意な ID の生成に Vue 3.5 の useId() を使います。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-use-id": "warn"
      }
    },
  },
});
vp run lint

悪い

id に Math.random() の値が含まれ、input と label の識別子がサーバーとクライアントの描画で異なる可能性があります。この例では、id という変数名から ID の生成箇所だと判定されます。

<script setup lang="ts">
const id = `input-${Math.random()}`;
</script>
<template><label :for="id">Name</label><input :id="id" /></template>

良い

Vue 3.5 以降の useId() で識別子を作り、:for と :id は同じ変数を参照し続けます。ランダムな値の生成を取り除きます。

<script setup lang="ts">
import { useId } from "vue";
const id = useId();
</script>
<template><label :for="id">Name</label><input :id="id" /></template>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-use-slots

setup の context.slots を useSlots() に置き換えます。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-use-slots": "warn"
      }
    },
  },
});
vp run lint

悪い

setup がコンテキスト引数から slots を分割代入で取り出しており、このルールが置換を推奨する参照形式です。

<script lang="ts">
import { defineComponent, h } from "vue";
export default defineComponent({
  setup(_props, { slots }) { return () => h("div", slots.default?.()); },
});
</script>

良い

setup 内で useSlots() からスロットを取得します。コンテキスト引数を使わず、レンダー関数と、デフォルトスロットが存在する場合だけ呼び出す処理を保ちます。

<script lang="ts">
import { defineComponent, h, useSlots } from "vue";
export default defineComponent({
  setup() {
    const slots = useSlots();
    return () => h("div", slots.default?.());
  },
});
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/prefer-use-template-ref

テンプレート参照に Vue 3.5 の useTemplateRef() を使います。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/prefer-use-template-ref": "warn"
      }
    },
  },
});
vp run lint

悪い

null で初期化した input の ref がテンプレートのリテラル ref="input" と対応し、null を許容する通常のデータではなく、要素参照であることが分かります。

<script setup lang="ts">
import { ref } from 'vue'
const input = ref<HTMLInputElement | null>(null)
</script>
<template>
  <input ref="input" />
</template>

良い

Vue 3.5 以降の useTemplateRef<HTMLInputElement>('input') でテンプレート参照を明示します。対応する要素参照のない error = ref(null) は通常のデータであり、このルールの対象外です。

<script setup lang="ts">
import { ref, useTemplateRef } from 'vue'
// Paired with the template ref below.
const input = useTemplateRef<HTMLInputElement>('input')
// A nullable data ref the template never binds as a ref.
const error = ref(null)
</script>
<template>
  <input ref="input" />
  <p>{{ error }}</p>
</template>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-default-prop

省略可能な、Boolean 以外の prop に default を用意します。

悪い例 · 良い例

既定の重大度: error
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-default-prop": "error"
      }
    },
  },
});
vp run lint

悪い

name と age は必須でない Boolean 以外の実行時 props で、未指定時の既定値がありません。

<script lang="ts">
export default {
  props: {
    // optional, non-Boolean, no default
    name: String,
    age: { type: Number },
  }
}
</script>

良い

name に default: '' を付けます。enabled は Boolean の暗黙の false を使い、必須の id には代替値が不要であるため、二つの除外条件も示しています。

<script lang="ts">
export default {
  props: {
    name: { type: String, default: '' },
    enabled: Boolean,                 // Boolean defaults to false
    id: { type: Number, required: true },
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-explicit-emits

emit するイベントを defineEmits または emits に宣言します。

悪い例 · 良い例

既定の重大度: warning
プリセット: happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-explicit-emits": "warn"
      }
    },
  },
});
vp run lint

悪い

受け取った emit 関数が save を送信しますが、defineEmits([]) にはそのイベントが宣言されていません。

<script setup lang="ts">
const emit = defineEmits([]);
emit("save");
</script>

良い

宣言に "save" を追加し、送信する文字列イベントをコンポーネントの明示的なイベント契約に含めます。

<script setup lang="ts">
const emit = defineEmits(["save"]);
emit("save");
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-explicit-slots

useSlots() で使う slot を defineSlots の型で宣言します。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-explicit-slots": "warn"
      }
    },
  },
});
vp run lint

悪い

型付きの defineProps<{ id: number }>() から、この例が TypeScript の構文を使っていることが分かります。しかし setup では defineSlots を宣言せずに useSlots() を使っており、利用するスロットの型が明示されていません。

<script setup lang="ts">
const props = defineProps<{ id: number }>()
const slots = useSlots()
</script>

良い

defineSlots で msg: string を props に持つ default slot を宣言し、useSlots() と明示的な型付き slot 契約を併記します。

<script setup lang="ts">
defineSlots<{ default(props: { msg: string }): unknown }>()
const slots = useSlots()
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-function-return-type

関数に戻り値の型注釈を指定します。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-function-return-type": "warn"
      }
    },
  },
});
vp run lint

悪い

add と greet は引数の型を指定していますが、戻り値の型を省略しています。この明示的な型指定の規則では、戻り値の推論だけでは条件を満たしません。

<script setup lang="ts">
const add = (a: number, b: number) => {
  return a + b
}

function greet(name: string) {
  return `Hello, ${name}`
}
</script>

良い

add に : number、greet に : string を付け、本体を変えずに戻り値の契約を明示します。

<script setup lang="ts">
const add = (a: number, b: number): number => {
  return a + b
}

function greet(name: string): string {
  return `Hello, ${name}`
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-prop-type-constructor

prop の type に文字列ではなくコンストラクターを指定します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-prop-type-constructor": "error"
      }
    },
  },
});
vp run lint

悪い

props の実行時の型に文字列 "String" と "Number" を使い、コンストラクターの配列にも文字列を入れています。これらの文字列はコンストラクター関数ではありません。

<script lang="ts">
export default {
  props: {
    // The type should be the `String` constructor, not the string "String".
    name: "String",
    age: { type: "Number" },
    id: { type: ["String", "Number"] }
  }
}
</script>

良い

型を実際の String と Number の識別子にし、共用型の配列も [String, Number] に変えます。

<script lang="ts">
export default {
  props: {
    name: String,
    age: { type: Number },
    id: { type: [String, Number] }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-prop-types

各 prop の型を宣言します。

悪い例 · 良い例

既定の重大度: error
プリセット: opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-prop-types": "error"
      }
    },
  },
});
vp run lint

悪い

配列の要素は status という名前だけを宣言しています。値を null にした prop と、空の設定オブジェクトを指定した prop にも、実行時の型宣言がありません。

<script lang="ts">
export default {
  props: ['status']            // array form: no types
}

export default {
  props: {
    status: null,              // no type
    other: {}                  // empty descriptor: no type
  }
}
</script>

良い

status: String でコンストラクターを直接指定し、other の設定オブジェクトに type: Number を付けます。両方の props に型が宣言されます。

<script lang="ts">
export default {
  props: {
    status: String,
    other: { type: Number, default: 0 }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-render-return

render 関数が値を返すことを必須にします。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-render-return": "error"
      }
    },
  },
});
vp run lint

悪い

render 関数が分岐の中で this.count を読むだけで、値を返していません。

<script lang="ts">
export default {
  render() {
    if (this.ready) {
      this.count
    }
  }
}
</script>

良い

render 関数は this.count を返します。

<script lang="ts">
export default {
  render() {
    return this.count
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-slots-as-functions

Vue 3 の $slots プロパティを関数として呼び出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-slots-as-functions": "error"
      }
    },
  },
});
vp run lint

悪い

render が this.$slots.default を呼び出さずに返しています。これは Vue 2 の vnode 配列です。

<script lang="ts">
export default {
  render() {
    return this.$slots.default
  }
}
</script>

良い

render は this.$slots.default() を呼び出し、その vnode を使います。

<script lang="ts">
export default {
  render() {
    return this.$slots.default()
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-symbol-provide

provide / inject のキーに衝突しにくい Symbol を使います。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-symbol-provide": "warn"
      }
    },
  },
});
vp run lint

悪い

provide と inject が 'user'、'theme' のような文字列キーを使い、同じ綴りを使うほかの provider と衝突し得ます。

<script setup lang="ts">
// String keys can collide
provide('user', user)
const user = inject('user')

// Magic strings are error-prone
provide('theme', { dark: true })
</script>

良い

共有する UserKey を Symbol で作り、InjectionKey<User> の型を付けます。両呼び出しに同じキーを渡し、文字列リテラルを使わないようにします。

<script lang="ts">
// Define injection key with Symbol
export const UserKey: InjectionKey<User> = Symbol('user')

// Provide with Symbol
provide(UserKey, user)

// Inject with Symbol
const user = inject(UserKey)
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-typed-object-prop

Object / Array の prop に具体的な型を指定します。

悪い例 · 良い例

既定の重大度: warning
プリセット: opinionated, nuxt
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-typed-object-prop": "warn"
      }
    },
  },
});
vp run lint

悪い

Object と Array コンストラクターだけでは、実行時にオブジェクトか配列かを示すにとどまり、user の構造や items の要素の型を表す具体的な静的型がありません。

<script setup lang="ts">
const props = defineProps({ user: Object, items: { type: Array } });
</script>

良い

PropType<User> と PropType<User[]> を付け、実行時のコンストラクターを保ったままオブジェクトと要素の型を指定します。

<script setup lang="ts">
import type { PropType } from "vue";
interface User { name: string }
const props = defineProps({
  user: Object as PropType<User>,
  items: { type: Array as PropType<User[]> },
});
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-typed-ref

引数なし、null、undefined で呼び出す ref() に型引数を指定します。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-typed-ref": "warn"
      }
    },
  },
});
vp run lint

悪い

インポートした ref に型引数がなく、引数なし、null、undefined からは将来代入する値の型を推論できません。

<script setup lang="ts">
import { ref } from 'vue'

const a = ref()           // Ref<undefined>
const b = ref(null)       // Ref<null>
const c = ref(undefined)  // Ref<undefined>
</script>

良い

型引数で string と、null を許容する User の ref を指定します。ref(0) には具体的な数値の初期値があり、型推論を使えます。

<script setup lang="ts">
import { ref } from 'vue'

const a = ref<string>()
const b = ref<User | null>(null)
const c = ref(0)          // inferred Ref<number>
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/require-valid-default-prop

prop の default を宣言した型に合う値にします。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/require-valid-default-prop": "error"
      }
    },
  },
});
vp run lint

悪い

Number と Boolean の props に型の合わないスカラー既定値を付け、Array と Object には factory ではなく共有されるリテラル値を使っています。

<script lang="ts">
export default {
  props: {
    count: { type: Number, default: '0' },     // string default for Number
    enabled: { type: Boolean, default: 1 },     // non-boolean default for Boolean
    items: { type: Array, default: [] },        // literal must be a factory
    config: { type: Object, default: {} }       // literal must be a factory
  }
}
</script>

良い

スカラーの既定値を 0 と false にし、配列とオブジェクトの既定値を新しい値を返す関数にします。[String, Number] の文字列既定値は、宣言した型の一つに合うため許可されます。

<script lang="ts">
export default {
  props: {
    count: { type: Number, default: 0 },
    enabled: { type: Boolean, default: false },
    items: { type: Array, default: () => [] },
    config: { type: Object, default: () => ({}) },
    label: { type: [String, Number], default: '' }
  }
}
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/return-in-computed-property

computed の getter に値を返す return を用意します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/return-in-computed-property": "error"
      }
    },
  },
});
vp run lint

悪い

ブロック形式の computed getter が 1 + 2 を計算するだけで返さず、computed の値が undefined になります。

<script setup lang="ts">
import { computed } from "vue";
const total = computed(() => { 1 + 2; });
</script>

良い

return 1 + 2 で計算結果をゲッターの戻り値にします。式文があるだけでは、このルールの条件を満たしません。ゲッター本体に、値を返す return が必要です。

<script setup lang="ts">
import { computed } from "vue";
const total = computed(() => { return 1 + 2; });
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/return-in-emits-validator

Options API の emits validator に戻り値を用意します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

この例では、現在の SFC フィルターが対象にする、関数本体を波括弧で囲んだアロー関数を使います。バリデーター自体はメソッドの省略記法にも対応していますが、現在の SFC 事前フィルターでは、その形式の検査が確実に呼び出されません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/return-in-emits-validator": "error"
      }
    },
  },
});
vp run lint

悪い

submit のバリデーターがペイロードをログ出力するだけで検査結果を返さず、関数の戻り値が undefined になります。

<script lang="ts">
export default { emits: { submit: (payload: unknown) => { console.log(payload); } } };
</script>

良い

return payload != null を追加し、ペイロードが null でも undefined でもないかを検査した結果を、真偽値で返します。

<script lang="ts">
export default { emits: { submit: (payload: unknown) => { return payload != null; } } };
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/valid-define-emits

defineEmits の重複や型と実行時引数の併用を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/valid-define-emits": "error"
      }
    },
  },
});
vp run lint

悪い

同じ defineEmits に型引数と実行時配列 ["save"] の両方を渡し、併用できない二つの宣言形式を混ぜています。

<script setup lang="ts">
defineEmits<{ save: [] }>(["save"]);
</script>

良い

実行時の引数を除き、save の宣言を型ベースの一つの形式に統一します。

<script setup lang="ts">
defineEmits<{ save: [] }>();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/valid-define-options

defineOptions の引数と使用回数を検査します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/valid-define-options": "error"
      }
    },
  },
});
vp run lint

悪い

最初の呼び出しが専用マクロで宣言すべき props を defineOptions に入れています。後続の呼び出しはマクロを繰り返し、オブジェクトでない引数も渡しています。禁止された形式と呼び出し回数の制約を示す例です。

<script setup lang="ts">
defineOptions({ props: ['foo'] })   // use defineProps instead
defineOptions({ name: 'Foo' })
defineOptions({ name: 'Bar' })      // duplicate call
defineOptions('Foo')                // not an object literal
</script>

良い

defineOptions を一度だけ呼び、通常の対応オプション name と inheritAttrs を持つオブジェクトを渡します。

<script setup lang="ts">
defineOptions({ name: 'Foo', inheritAttrs: false })
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/valid-define-props

defineProps の重複や型と実行時引数の併用を検出します。

悪い例 · 良い例

既定の重大度: error
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/valid-define-props": "error"
      }
    },
  },
});
vp run lint

悪い

同じ defineProps に型引数 { title: string } と実行時引数 { title: String } の両方を渡しています。コンパイラーはこの併用を許可しません。

<script setup lang="ts">
defineProps<{ title: string }>({ title: String });
</script>

良い

実行時オブジェクトを除き、二つの形式を併用せず title の型ベースの宣言だけを残します。

<script setup lang="ts">
defineProps<{ title: string }>();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

script/valid-next-tick

nextTick() の完了を await、then、またはコールバックで扱います。

悪い例 · 良い例

既定の重大度: warning
プリセット: essential, happy-path, ecosystem, nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の JavaScript / TypeScript の script ブロック。対象となる Options API または script setup の形式は例を参照してください。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "script/valid-next-tick": "warn"
      }
    },
  },
});
vp run lint

悪い

インポートした nextTick() をコールバックなしの式文で呼び、返された Promise を無視しています。DOM 更新後まで待つ処理がありません。

<script setup lang="ts">
import { nextTick } from "vue";
nextTick();
</script>

良い

await nextTick() で Promise を使い、後続の setup 処理へ進む前に次の DOM 更新を明示的に待ちます。

<script setup lang="ts">
import { nextTick } from "vue";
await nextTick();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

type/no-floating-promises

処理しないまま放置された Promise を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の script とテンプレートの型情報。例に示した構文が対象です。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

型情報を使う検査には、ネイティブの Corsa ランタイムと TypeScript プロジェクトが必要です。typeAware を有効にしても、個別の有効化が必要なルールは自動では有効になりません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "type/no-floating-promises": "warn"
      },
      "typeAware": true
    },
  },
});
vp run lint

悪い

async の save は Promise を返しますが、単独の save() 呼び出しが await も return もせず、意図的に捨てる指定もありません。

<script setup lang="ts">
async function save(): Promise<void> {}
save();
</script>

良い

void save() で Promise の完了を待たずに結果を破棄する意図を明示し、このルールの条件を満たします。この指定は Promise の拒否を処理するものではありません。

<script setup lang="ts">
async function save(): Promise<void> {}
void save();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

type/no-reactivity-loss

リアクティブな値を代入や呼び出しで取り出し、元の更新に追従しないスナップショットになる箇所を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の script とテンプレートの型情報。例に示した構文が対象です。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

型情報を使う検査には、ネイティブの Corsa ランタイムと TypeScript プロジェクトが必要です。typeAware を有効にしても、個別の有効化が必要なルールは自動では有効になりません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "type/no-reactivity-loss": "warn"
      },
      "typeAware": true
    },
  },
});
vp run lint

悪い

const count = state.count がリアクティブなプロパティから数値のスナップショットを取り、その後の state.count の更新が変数へ反映されなくなります。

<script setup lang="ts">
import { reactive } from "vue";
const state = reactive({ count: 0 });
const count = state.count;
</script>

良い

toRef(state, "count") で現在のプリミティブ値をコピーせず、count を元のリアクティブなプロパティにつなげます。

<script setup lang="ts">
import { reactive, toRef } from "vue";
const state = reactive({ count: 0 });
const count = toRef(state, "count");
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

type/no-unsafe-template-binding

テンプレートで安全でない型の値を使用する箇所を検出します。

悪い例 · 良い例

既定の重大度: warning
プリセット: nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の script とテンプレートの型情報。例に示した構文が対象です。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

型情報を使う検査には、ネイティブの Corsa ランタイムと TypeScript プロジェクトが必要です。typeAware を有効にしても、個別の有効化が必要なルールは自動では有効になりません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "type/no-unsafe-template-binding": "warn"
      },
      "typeAware": true
    },
  },
});
vp run lint

悪い

補間する value の型を明示的に any としているため、型チェッカーはテンプレートに結び付ける値を、安全な具体的な型として検査できません。

<script setup lang="ts">
const value: any = "Hello";
</script>
<template><p>{{ value }}</p></template>

良い

型注釈を string に変え、描画する値を変えずに、同じ補間へ検査できる具体的な型を与えます。

<script setup lang="ts">
const value: string = "Hello";
</script>
<template><p>{{ value }}</p></template>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

type/require-typed-emits

defineEmits に型定義を指定します。

悪い例 · 良い例

既定の重大度: warning
プリセット: happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の script とテンプレートの型情報。例に示した構文が対象です。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

型情報を使う検査には、ネイティブの Corsa ランタイムと TypeScript プロジェクトが必要です。typeAware を有効にしても、個別の有効化が必要なルールは自動では有効になりません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "type/require-typed-emits": "warn"
      },
      "typeAware": true
    },
  },
});
vp run lint

悪い

配列だけの defineEmits(["save"]) はイベント名を宣言するだけで、ペイロードの型が宣言されていません。

<script setup lang="ts">
defineEmits(["save"]);
</script>

良い

defineEmits<{ save: [] }>() で、ペイロードを空のタプル型として宣言します。これにより、save イベントがペイロードの引数を受け取らないことを明示します。

<script setup lang="ts">
defineEmits<{ save: [] }>();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

type/require-typed-props

defineProps に型定義を指定します。

悪い例 · 良い例

既定の重大度: warning
プリセット: happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の script とテンプレートの型情報。例に示した構文が対象です。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。

型情報を使う検査には、ネイティブの Corsa ランタイムと TypeScript プロジェクトが必要です。typeAware を有効にしても、個別の有効化が必要なルールは自動では有効になりません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "type/require-typed-props": "warn"
      },
      "typeAware": true
    },
  },
});
vp run lint

悪い

配列だけの defineProps(["title"]) は title の名前だけを宣言し、型を指定していません。

<script setup lang="ts">
defineProps(["title"]);
</script>

良い

defineProps<{ title: string }>() で、名前だけの実行時宣言に代えて title の string 型を明示します。

<script setup lang="ts">
defineProps<{ title: string }>();
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール

type/strict-boolean-expressions

script とテンプレートの条件式で安全な真偽判定を使います。

悪い例 · 良い例

既定の重大度: warning
プリセット: none
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC の script とテンプレートの型情報。例に示した構文が対象です。
オプション: 型付きオプションと既定値を参照してください。

typeAware とこのルールを明示的に有効にします。既定では null または undefined を含み得る数値は許可されず、どちらも含まない数値は許可されます。

型情報を使う検査には、ネイティブの Corsa ランタイムと TypeScript プロジェクトが必要です。typeAware を有効にしても、個別の有効化が必要なルールは自動では有効になりません。

設定(Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  vue: {
    linter: {
      "preset": "incremental",
      "rules": {
        "type/strict-boolean-expressions": "warn"
      },
      "typeAware": true
    },
  },
});
vp run lint

悪い

if (count) は、undefined を含み得る数値をそのまま真偽判定に使い、明示的な真偽値の比較をしていません。数値のゼロと値の未指定を、どちらも偽として扱ってしまいます。

<script setup lang="ts">
const count: number | undefined = undefined;
if (count) console.log(count);
</script>

良い

count !== undefined && count > 0 で、値が undefined でないことと正の数であることを別々に検査します。省略可能な値を絞り込んでから、真偽値を返す条件式で判定します。

<script setup lang="ts">
const count: number | undefined = undefined;
if (count !== undefined && count > 0) console.log(count);
</script>

良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。

実装 · 全ルール