mcpField
Y
ycs77-vue

ycs77-vue

github.com/ycs77開発038 回インストール1 週間前に更新
リポジトリ

ycs77-vue について

ycs77-vue は、読みやすくボイラープレートの少ないコードを目指す Vue 3 と TypeScript の開発者向けコーディング規約スキルです。コンポーネント構成、型宣言、リアクティブな状態管理の規則をまとめています。

主な機能

  1. 01TypeScript の書式規約
  2. 02Vue SFC のブロック順序
  3. 03props と emits のインライン型
  4. 04reactive() によるフォーム状態管理
  5. 05複雑な型に対する ref() の書き方
  6. 06テンプレート内の props アクセス規則

活用シーン

  1. 01Vue 3 プロジェクトのコードスタイル統一
  2. 02コンポーネントの props と emits の型整理
  3. 03フォームや複雑なリアクティブ状態の管理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ycs77/skills --skill ycs77-vue

インストール後、Claude Code で/ycs77-vueを入力して読み込まれたか確認します。

詳細

Lucas Yang の Vue 規約

実際のプロジェクトで、ボイラープレートを最小限に抑え、読みやすさと実用的なシンプルさを重視する、独自の見解に基づいた Vue 3 と TypeScript のパターンです。

TypeScript のフォーマット

標準:スペース 2 つ、シングルクォート、セミコロンなし、末尾のカンマあり。

Vue SFC のパターン

1. SFC のブロック順序

Single File Components では、常に <template> を <script setup lang="ts"> より前に配置します。これは、構造(何をレンダリングするか)から動作(どのように機能するか)へと進む、自然な読み順に沿ったものです。

推奨:

<template>
  <div class="container">
    <h1>{{ title }}</h1>
  </div>
</template>

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

const title = ref('Hello World')
</script>
2. props と emits のインライン型

コンポーネント API が呼び出し元から見えるように、defineProps と defineEmits ではインライン型を使用します。

推奨:

<script setup lang="ts">
const props = defineProps<{
  title: string
  count?: number
  items: {
    id: string
    name: string
  }[]
}>()

const emit = defineEmits<{
  update: [value: string]
  delete: [id: string]
}>()
</script>

例外:型が複数のコンポーネントで再利用される場合、またはエクスポートが必要な場合に限り、別のインターフェースに切り出します。

3. フォームの状態には reactive() を使用する

フォームの状態を管理する場合は、すべてのフォームフィールドを保持する 1 つのリアクティブオブジェクトを作成するために、reactive() を使用します。この方法では、各フィールドに複数の ref() を使う場合と比べて、状態管理が簡潔になり、ボイラープレートコードを減らせます。

推奨:

<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="form.email" type="email">
    <input v-model="form.password" type="password">
    <input v-model="form.rememberMe" type="checkbox">
  </form>
</template>

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

const form = reactive({
  email: '',
  password: '',
  rememberMe: false,
})

function handleSubmit() {
  console.log(form) // Clean object or reactive object, easy to submit
}

function resetForm() {
  form.email = ''
  form.password = ''
  form.rememberMe = false
}
</script>

理由:関連する状態をまとめることで、.value のボイラープレートが減り、フォームの送信処理もすっきりします。個々の ref() は、本当に独立した状態にのみ使用します。

4. 複雑な型の ref() には型アサーションを使用する

インターフェース型や複雑なオブジェクト型には、Vue のディープアンラップによる型の競合を避けるため、ref<Type>(value) よりも ref(value) as Ref<Type> を使用します。値がアサーションした型を満たしていることを確認してください。プリミティブ型と列挙型には ref<Type>() を使用します。

オブジェクトが存在しない場合は、undefined よりも null を使用します。

推奨:

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

interface User {
  id: number
  name: string
}

enum Status {
  Pending = 'pending',
}

// Complex type - use type assertion
const user = ref({ id: 1, name: 'Lucas' }) as Ref<User>
const users = ref([]) as Ref<User[]>
const isSelectedUser = ref(null) as Ref<User | null>

// Primitive types - generic parameter is fine
const count = ref<number>(0)
const isActive = ref<boolean>(false)
const status = ref<Status>(Status.Pending)
</script>

避ける:

<script setup lang="ts">
import type { User } from '@/types'
import { ref } from 'vue'

// May cause: Type '...' is not assignable to type 'Ref<User>'
const user = ref<User>()
</script>
5. バインディングには同名の省略記法を使用する

Vue 3.4 以降では、一致するバインディングに同名の省略記法を使用します。

推奨:

<template>
  <div :id :title>
    <MyComponent :user-name :count :is-active />
  </div>
</template>

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

const id = ref('app')
const title = ref('Dashboard')
const userName = ref('Lucas')
const count = ref(42)
const isActive = ref(true)
</script>

理由::user-name は userName に対応します(ケバブケースからキャメルケースへの変換)。セクション 6 のように、props. による明示的なアクセスが必要な場合は、省略せずに記述します。

6. テンプレートから props に直接アクセスする

defineProps で宣言した props は、<template> 内で名前を使って参照できます。曖昧さがない場合は、{{ props.title }} よりも {{ title }} を使用します。ローカルバインディングが prop と名前の競合を起こす場合は、props.name を使用します。class(JavaScript の予約語)や as(TypeScript の型アサーションで使用)のように、構文上注意が必要な名前には、props.class や props.as のように明示的にアクセスします。:class の省略記法では、式として単独の class を使用できません。また、:is="as" では、as の出どころが明確になりません。

推奨:

<template>
  <div :class="props.class">
    <h1>{{ title }}</h1>
    <component :is="props.as">content</component>
  </div>
</template>

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

const props = defineProps<{
  title: string
  as: string
  class?: HTMLAttributes['class']
}>()
</script>

避ける:

<div :class>
  <component :is="as">content</component>
</div>

コメント