Agent Skills: Vue TypeScript Skill

Master Vue TypeScript - Type-safe Components, Generics, Type Inference, Advanced Patterns

UncategorizedID: pluginagentmarketplace/custom-plugin-vue/vue-typescript

Skill Files

Browse the full folder contents for vue-typescript.

Download Skill

Loading file tree…

skills/vue-typescript/SKILL.md

Skill Metadata

Name
vue-typescript
Description
Master Vue TypeScript - Type-safe Components, Generics, Type Inference, Advanced Patterns

Vue TypeScript Skill

Production-grade skill for mastering TypeScript integration with Vue 3 applications.

Purpose

Single Responsibility: Teach TypeScript integration with Vue including typed components, generics, type inference, and advanced type patterns.

Parameter Schema

interface VueTypeScriptParams {
  topic: 'config' | 'components' | 'generics' | 'stores' | 'inference' | 'all';
  level: 'beginner' | 'intermediate' | 'advanced';
  context?: {
    strict_mode?: boolean;
    existing_js?: boolean;
  };
}

Learning Modules

Module 1: TypeScript Setup

Prerequisites: vue-fundamentals, TypeScript basics
Duration: 1-2 hours
Outcome: Configure TypeScript for Vue

| Topic | File | Content | |-------|------|---------| | tsconfig | tsconfig.json | Vue-specific config | | Volar | Extension | IDE support | | env.d.ts | Type declarations | Vite/Vue types | | vue-tsc | Build check | Type validation |

tsconfig.json:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "jsx": "preserve",
    "jsxImportSource": "vue"
  },
  "include": ["src/**/*.ts", "src/**/*.vue"]
}

Module 2: Typed Components

Prerequisites: Module 1
Duration: 3-4 hours
Outcome: Write type-safe components

| Feature | Syntax | Exercise | |---------|--------|----------| | Props | defineProps<Props>() | Typed props | | Emits | defineEmits<Emits>() | Typed events | | Defaults | withDefaults() | Default values | | Expose | defineExpose() | Public API | | Slots | defineSlots() | Typed slots |

Typed Component:

<script setup lang="ts">
interface Props {
  title: string
  count?: number
  items: Item[]
}

interface Emits {
  (e: 'update', value: string): void
  (e: 'select', item: Item): void
}

const props = withDefaults(defineProps<Props>(), {
  count: 0
})

const emit = defineEmits<Emits>()
</script>

Module 3: Generic Components

Prerequisites: Module 2
Duration: 3 hours
Outcome: Build reusable generic components

Generic Component:

<script setup lang="ts" generic="T extends { id: string | number }">
interface Props {
  items: T[]
  selected?: T
}

interface Emits {
  (e: 'select', item: T): void
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()
</script>

<template>
  <ul>
    <li v-for="item in items" :key="item.id" @click="emit('select', item)">
      <slot :item="item" />
    </li>
  </ul>
</template>

Module 4: Typed Composables & Stores

Prerequisites: Module 3
Duration: 3-4 hours
Outcome: Type-safe reusable logic

| Pattern | Typing Technique | Exercise | |---------|------------------|----------| | Composable return | Interface | useFetch<T> | | Store state | Typed refs | User store | | Getters | Computed types | Derived state | | Actions | Async types | API actions |

Typed Composable:

interface UseFetchReturn<T> {
  data: Ref<T | null>
  error: Ref<Error | null>
  loading: Ref<boolean>
  execute: () => Promise<void>
}

export function useFetch<T>(url: MaybeRefOrGetter<string>): UseFetchReturn<T> {
  const data = ref<T | null>(null) as Ref<T | null>
  // ...
  return { data, error, loading, execute }
}

Module 5: Advanced Type Patterns

Prerequisites: Modules 1-4
Duration: 3-4 hours
Outcome: Expert-level Vue typing

| Pattern | Use Case | Example | |---------|----------|---------| | Utility types | Props extraction | ExtractProps<T> | | Module augmentation | Route meta | RouteMeta interface | | Conditional types | API responses | ResponseType<T> | | Template refs | Component refs | ComponentRef<T> |

Utility Types:

// Extract props from component
type ExtractProps<T> = T extends new () => { $props: infer P } ? P : never

// Deep partial
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
}

// Component ref type
type ComponentRef<T> = T extends new () => infer R ? R : never
const buttonRef = ref<ComponentRef<typeof Button> | null>(null)

Validation Checkpoints

Beginner Checkpoint

  • [ ] Configure tsconfig for Vue
  • [ ] Use defineProps with types
  • [ ] Use defineEmits with types
  • [ ] Fix basic type errors

Intermediate Checkpoint

  • [ ] Create generic component
  • [ ] Type composable return values
  • [ ] Type Pinia store
  • [ ] Use withDefaults correctly

Advanced Checkpoint

  • [ ] Implement utility types
  • [ ] Augment route meta types
  • [ ] Type complex generics
  • [ ] Achieve zero any types

Retry Logic

const skillConfig = {
  maxAttempts: 3,
  backoffMs: [1000, 2000, 4000],
  onFailure: 'simplify_type_definition'
}

Observability

tracking:
  - event: type_error_fixed
    data: [error_code, file]
  - event: pattern_learned
    data: [pattern_name, complexity]
  - event: skill_completed
    data: [strict_mode, any_count]

Troubleshooting

Common Issues

| Issue | Cause | Solution | |-------|-------|----------| | defineProps not typed | Missing generic | Add <Props> | | Cannot find module | Missing declaration | Add env.d.ts | | Generic not working | Vue < 3.3 | Upgrade Vue | | Type not inferred | Complex type | Explicit annotation |

Debug Steps

  1. Check Volar is enabled
  2. Run vue-tsc for errors
  3. Verify tsconfig paths
  4. Check type imports

Unit Test Template

import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import GenericList from './GenericList.vue'

interface User {
  id: number
  name: string
}

describe('GenericList', () => {
  it('renders items with correct types', () => {
    const users: User[] = [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' }
    ]

    const wrapper = mount(GenericList<User>, {
      props: { items: users },
      slots: {
        default: ({ item }: { item: User }) => item.name
      }
    })

    expect(wrapper.text()).toContain('Alice')
    expect(wrapper.text()).toContain('Bob')
  })

  it('emits typed select event', async () => {
    const users: User[] = [{ id: 1, name: 'Alice' }]
    const wrapper = mount(GenericList<User>, {
      props: { items: users }
    })

    await wrapper.find('li').trigger('click')
    const emitted = wrapper.emitted('select')
    expect(emitted?.[0][0]).toEqual({ id: 1, name: 'Alice' })
  })
})

Usage

Skill("vue-typescript")

Related Skills

  • vue-fundamentals - Prerequisite
  • vue-composition-api - For typed composables
  • vue-testing - Type-safe testing

Resources