All skills
hyf0 avatar

/vue-options-api-best-practices

@bc922e4 official
by hyf0hyf0/vue-skills2.9k stars
167

Vue 3 Options API style (data(), methods, this context). Each reference shows Options API solution only.

Use this Skill: https://skilld.dev/gh/hyf0/vue-skills/vue-options-api-best-practices

This session only. Nothing lands on disk.

referencets-options-api-use-definecomponent.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Always Use defineComponent for TypeScript Type Inference

Impact: HIGH - When using TypeScript with Vue's Options API, you MUST wrap your component definition with defineComponent() to enable proper type inference. Without it, this is typed as any, losing all TypeScript benefits.

Task Checklist

  • Always import and use defineComponent from 'vue' for Options API components
  • Enable strict: true (or at minimum noImplicitThis: true) in tsconfig.json
  • Consider migrating to Composition API with <script setup> for better type inference

The Problem

Vue's Options API relies heavily on the this context, which TypeScript cannot automatically type without defineComponent:

BAD - No type inference:

// No defineComponent - 'this' is typed as 'any'
export default {
  props: {
    message: String
  },
  computed: {
    // 'this' is 'any' - no type checking!
    greeting() {
      return this.message + '!'  // No type inference
    }
  },
  methods: {
    // 'this' is 'any' - mistakes won't be caught
    handleClick() {
      console.log(this.mesage)  // Typo not caught!
    }
  }
}

GOOD - Full type inference:

import { defineComponent } from 'vue'

export default defineComponent({
  props: {
    message: {
      type: String,
      required: true
    },
    count: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      localState: ''
    }
  },
  computed: {
    // 'this.message' is typed as string
    // 'this.count' is typed as number
    greeting(): string {
      return this.message + '!'
    }
  },
  methods: {
    handleClick() {
      console.log(this.mesage)  // Error: Property 'mesage' does not exist
      console.log(this.message)  // OK: string
    }
  }
})

What defineComponent Enables

  1. Props type inference: Vue infers types from type, required, and default
  2. this context typing: All options (data, computed, methods) are properly typed
  3. Cross-option references: Access data in methods, computed properties, etc. with full types
  4. IDE autocompletion: Get suggestions for all component properties and methods

TypeScript Configuration Required

For proper this type checking, enable strict mode or at minimum noImplicitThis:

// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    // Or at minimum:
    "noImplicitThis": true
  }
}

Without this, TypeScript allows implicit any for this, defeating the purpose of using defineComponent.

defineComponent is a No-Op at Runtime

defineComponent does nothing at runtime - it simply returns the object you pass to it. Its only purpose is to help TypeScript infer types:

// At runtime, this is equivalent to:
// export default { props: { ... }, ... }
export default defineComponent({
  props: { /* ... */ }
})

This means there's zero runtime cost to using defineComponent.

When to Use defineComponent vs script setup

Approach Use Case
defineComponent Options API, Class-based migration, JSX/TSX components
<script setup> New components, better type inference, less boilerplate

Official recommendation: "While Vue does support TypeScript usage with Options API, it is recommended to use Vue with TypeScript via Composition API as it offers simpler, more efficient and more robust type inference."

With Vue Single-File Components

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

export default defineComponent({
  name: 'MyComponent',
  props: {
    title: {
      type: String,
      required: true
    }
  },
  computed: {
    upperTitle(): string {
      return this.title.toUpperCase()
    }
  }
})
</script>

<template>
  <h1>{{ upperTitle }}</h1>
</template>

Common Mistake: Missing defineComponent

This often happens when copying JavaScript components to TypeScript:

// Copied from JS - MISSING defineComponent!
export default {
  name: 'MyComponent',
  // ... entire component without type inference
}

Always add defineComponent when converting to TypeScript.

Reference

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides comprehensive best practices and TypeScript integration guidelines for the Vue.js Options API. It contains educational content and code examples that are safe and consistent with official Vue.js documentation. No security issues were detected.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    11 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at bc922e4. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 8 months ago
version
2.0.0
author
github.com/vuejs-ai
  • Vue
  • TypeScript
  • options-api
  • best-practices
  • lifecycle-hooks
  • prop-types
  • type-safety

README badge

README badge for hyf0/vue-skills/vue-options-api-best-practices

Teaches Vue 3 Options API patterns, TypeScript integration, and common mistakes like arrow functions in methods and lifecycle hooks. Covers prop typing, event handler safety, provide/inject limitations, and computed property type inference specific to the Options API style.

Generated from the current SKILL.md.

Does this skill cover Composition API?
No. This skill focuses exclusively on Options API patterns and does not include Composition API examples or guidance.
What TypeScript support does this provide?
The skill includes references for enabling type inference with defineComponent, typing event handlers, complex prop types, provide/inject limitations, and computed property return types in the Options API context.
Does this address method binding issues?
Yes. The skill covers arrow function pitfalls in methods and lifecycle hooks, which commonly break this context binding in the Options API.

Generated from the current SKILL.md. These answers refresh after source changes.