@pythoughts/vue-skills-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +63 -0
  2. package/index.mjs +139 -0
  3. package/package.json +34 -0
  4. package/skills/create-adaptable-composable/SKILL.md +76 -0
  5. package/skills/vue-best-practices/SKILL.md +154 -0
  6. package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
  7. package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
  8. package/skills/vue-best-practices/references/component-async.md +97 -0
  9. package/skills/vue-best-practices/references/component-data-flow.md +350 -0
  10. package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
  11. package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
  12. package/skills/vue-best-practices/references/component-slots.md +216 -0
  13. package/skills/vue-best-practices/references/component-suspense.md +228 -0
  14. package/skills/vue-best-practices/references/component-teleport.md +108 -0
  15. package/skills/vue-best-practices/references/component-transition-group.md +128 -0
  16. package/skills/vue-best-practices/references/component-transition.md +125 -0
  17. package/skills/vue-best-practices/references/composables.md +290 -0
  18. package/skills/vue-best-practices/references/directives.md +162 -0
  19. package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
  20. package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
  21. package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
  22. package/skills/vue-best-practices/references/plugins.md +166 -0
  23. package/skills/vue-best-practices/references/reactivity.md +346 -0
  24. package/skills/vue-best-practices/references/render-functions.md +201 -0
  25. package/skills/vue-best-practices/references/sfc.md +310 -0
  26. package/skills/vue-best-practices/references/state-management.md +135 -0
  27. package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
  28. package/skills/vue-debug-guides/SKILL.md +205 -0
  29. package/skills/vue-debug-guides/reference/animation-key-for-rerender.md +160 -0
  30. package/skills/vue-debug-guides/reference/animation-transitiongroup-performance.md +241 -0
  31. package/skills/vue-debug-guides/reference/async-component-error-handling.md +115 -0
  32. package/skills/vue-debug-guides/reference/async-component-keepalive-ref-issue.md +112 -0
  33. package/skills/vue-debug-guides/reference/async-component-suspense-control.md +84 -0
  34. package/skills/vue-debug-guides/reference/async-component-vue-router.md +109 -0
  35. package/skills/vue-debug-guides/reference/attrs-event-listener-merging.md +205 -0
  36. package/skills/vue-debug-guides/reference/checkbox-true-false-value-form-submission.md +118 -0
  37. package/skills/vue-debug-guides/reference/cleanup-side-effects.md +172 -0
  38. package/skills/vue-debug-guides/reference/click-events-on-components.md +180 -0
  39. package/skills/vue-debug-guides/reference/component-naming-conflicts.md +159 -0
  40. package/skills/vue-debug-guides/reference/component-ref-requires-defineexpose.md +176 -0
  41. package/skills/vue-debug-guides/reference/composable-avoid-hidden-side-effects.md +208 -0
  42. package/skills/vue-debug-guides/reference/composable-call-location-restrictions.md +141 -0
  43. package/skills/vue-debug-guides/reference/composable-naming-return-pattern.md +139 -0
  44. package/skills/vue-debug-guides/reference/composable-tovalue-inside-watcheffect.md +182 -0
  45. package/skills/vue-debug-guides/reference/composition-api-not-functional-programming.md +120 -0
  46. package/skills/vue-debug-guides/reference/composition-api-script-setup-async-context.md +203 -0
  47. package/skills/vue-debug-guides/reference/composition-api-vs-react-hooks-differences.md +156 -0
  48. package/skills/vue-debug-guides/reference/computed-array-mutation.md +148 -0
  49. package/skills/vue-debug-guides/reference/computed-conditional-dependencies.md +147 -0
  50. package/skills/vue-debug-guides/reference/computed-no-parameters.md +159 -0
  51. package/skills/vue-debug-guides/reference/computed-no-side-effects.md +107 -0
  52. package/skills/vue-debug-guides/reference/computed-return-value-readonly.md +160 -0
  53. package/skills/vue-debug-guides/reference/configure-app-before-mount.md +89 -0
  54. package/skills/vue-debug-guides/reference/declare-emits-for-documentation.md +212 -0
  55. package/skills/vue-debug-guides/reference/define-expose-before-await.md +192 -0
  56. package/skills/vue-debug-guides/reference/define-model-default-value-sync.md +139 -0
  57. package/skills/vue-debug-guides/reference/defineEmits-must-be-top-level.md +164 -0
  58. package/skills/vue-debug-guides/reference/defineEmits-no-runtime-and-type-mixed.md +170 -0
  59. package/skills/vue-debug-guides/reference/definemodel-object-mutation-no-emit.md +148 -0
  60. package/skills/vue-debug-guides/reference/dom-update-timing-nexttick.md +90 -0
  61. package/skills/vue-debug-guides/reference/dynamic-argument-constraints.md +146 -0
  62. package/skills/vue-debug-guides/reference/dynamic-component-registration-vite.md +147 -0
  63. package/skills/vue-debug-guides/reference/event-modifier-order-matters.md +101 -0
  64. package/skills/vue-debug-guides/reference/exact-modifier-for-precise-shortcuts.md +155 -0
  65. package/skills/vue-debug-guides/reference/fallthrough-attrs-overwrite-vue3.md +159 -0
  66. package/skills/vue-debug-guides/reference/in-dom-template-parsing-caveats.md +149 -0
  67. package/skills/vue-debug-guides/reference/inheritattrs-false-for-wrapper-components.md +230 -0
  68. package/skills/vue-debug-guides/reference/keepalive-router-nested-double-mount.md +222 -0
  69. package/skills/vue-debug-guides/reference/keepalive-transition-memory-leak.md +144 -0
  70. package/skills/vue-debug-guides/reference/keyup-modifier-timing.md +137 -0
  71. package/skills/vue-debug-guides/reference/lifecycle-dom-access-timing.md +216 -0
  72. package/skills/vue-debug-guides/reference/lifecycle-hooks-synchronous-registration.md +156 -0
  73. package/skills/vue-debug-guides/reference/lifecycle-ssr-awareness.md +184 -0
  74. package/skills/vue-debug-guides/reference/local-components-not-in-descendants.md +151 -0
  75. package/skills/vue-debug-guides/reference/mount-return-value.md +88 -0
  76. package/skills/vue-debug-guides/reference/multi-root-component-class-attrs.md +93 -0
  77. package/skills/vue-debug-guides/reference/native-event-collision-with-emits.md +162 -0
  78. package/skills/vue-debug-guides/reference/no-passive-with-prevent.md +141 -0
  79. package/skills/vue-debug-guides/reference/no-v-if-with-v-for.md +136 -0
  80. package/skills/vue-debug-guides/reference/perf-computed-object-stability.md +157 -0
  81. package/skills/vue-debug-guides/reference/perf-props-stability-update-optimization.md +140 -0
  82. package/skills/vue-debug-guides/reference/plugin-global-properties-sparingly.md +109 -0
  83. package/skills/vue-debug-guides/reference/plugin-install-before-mount.md +124 -0
  84. package/skills/vue-debug-guides/reference/plugin-prefer-provide-inject-over-global-properties.md +120 -0
  85. package/skills/vue-debug-guides/reference/plugin-typescript-type-augmentation.md +157 -0
  86. package/skills/vue-debug-guides/reference/prop-defineprops-scope-limitation.md +161 -0
  87. package/skills/vue-debug-guides/reference/provide-inject-debugging-challenges.md +203 -0
  88. package/skills/vue-debug-guides/reference/provide-inject-default-value-factory.md +244 -0
  89. package/skills/vue-debug-guides/reference/provide-inject-reactivity-not-automatic.md +226 -0
  90. package/skills/vue-debug-guides/reference/provide-inject-synchronous-setup.md +235 -0
  91. package/skills/vue-debug-guides/reference/reactive-destructuring.md +89 -0
  92. package/skills/vue-debug-guides/reference/reactivity-debugging-hooks.md +132 -0
  93. package/skills/vue-debug-guides/reference/reactivity-markraw-for-non-reactive.md +149 -0
  94. package/skills/vue-debug-guides/reference/reactivity-proxy-identity-hazard.md +96 -0
  95. package/skills/vue-debug-guides/reference/reactivity-same-tick-batching.md +166 -0
  96. package/skills/vue-debug-guides/reference/ref-value-access.md +61 -0
  97. package/skills/vue-debug-guides/reference/refs-in-collections-need-value.md +81 -0
  98. package/skills/vue-debug-guides/reference/render-function-avoid-internal-vnode-properties.md +151 -0
  99. package/skills/vue-debug-guides/reference/render-function-vnodes-must-be-unique.md +133 -0
  100. package/skills/vue-debug-guides/reference/rendering-render-function-h-import-vue3.md +148 -0
  101. package/skills/vue-debug-guides/reference/rendering-render-function-return-from-setup.md +148 -0
  102. package/skills/vue-debug-guides/reference/rendering-render-function-slots-as-functions.md +168 -0
  103. package/skills/vue-debug-guides/reference/rendering-resolve-component-for-string-names.md +231 -0
  104. package/skills/vue-debug-guides/reference/select-initial-value-ios-bug.md +91 -0
  105. package/skills/vue-debug-guides/reference/self-referencing-component-name.md +157 -0
  106. package/skills/vue-debug-guides/reference/sfc-named-exports-forbidden.md +184 -0
  107. package/skills/vue-debug-guides/reference/sfc-scoped-css-child-component-styling.md +156 -0
  108. package/skills/vue-debug-guides/reference/sfc-scoped-css-dynamic-content.md +193 -0
  109. package/skills/vue-debug-guides/reference/sfc-scoped-css-slot-content.md +242 -0
  110. package/skills/vue-debug-guides/reference/sfc-script-setup-reactivity.md +195 -0
  111. package/skills/vue-debug-guides/reference/slot-forwarding-to-child-components.md +143 -0
  112. package/skills/vue-debug-guides/reference/slot-implicit-default-content.md +155 -0
  113. package/skills/vue-debug-guides/reference/slot-name-reserved-prop.md +109 -0
  114. package/skills/vue-debug-guides/reference/slot-named-scoped-explicit-default.md +95 -0
  115. package/skills/vue-debug-guides/reference/slot-render-scope-parent-only.md +135 -0
  116. package/skills/vue-debug-guides/reference/slot-v-slot-on-components-or-templates-only.md +122 -0
  117. package/skills/vue-debug-guides/reference/ssr-hydration-mismatch-causes.md +280 -0
  118. package/skills/vue-debug-guides/reference/ssr-platform-specific-apis.md +256 -0
  119. package/skills/vue-debug-guides/reference/state-ssr-cross-request-pollution.md +276 -0
  120. package/skills/vue-debug-guides/reference/suspense-no-builtin-error-handling.md +127 -0
  121. package/skills/vue-debug-guides/reference/suspense-ssr-hydration-issues.md +159 -0
  122. package/skills/vue-debug-guides/reference/tailwind-dynamic-class-generation.md +144 -0
  123. package/skills/vue-debug-guides/reference/teleport-scoped-styles-limitation.md +191 -0
  124. package/skills/vue-debug-guides/reference/teleport-ssr-hydration.md +152 -0
  125. package/skills/vue-debug-guides/reference/teleport-target-must-exist.md +113 -0
  126. package/skills/vue-debug-guides/reference/template-expressions-restrictions.md +114 -0
  127. package/skills/vue-debug-guides/reference/template-functions-no-side-effects.md +187 -0
  128. package/skills/vue-debug-guides/reference/template-ref-null-with-v-if.md +123 -0
  129. package/skills/vue-debug-guides/reference/template-ref-unwrapping-top-level.md +104 -0
  130. package/skills/vue-debug-guides/reference/template-ref-v-for-order.md +172 -0
  131. package/skills/vue-debug-guides/reference/textarea-no-interpolation.md +72 -0
  132. package/skills/vue-debug-guides/reference/transition-group-flip-inline-elements.md +152 -0
  133. package/skills/vue-debug-guides/reference/transition-group-move-animation-position-absolute.md +130 -0
  134. package/skills/vue-debug-guides/reference/transition-group-no-default-wrapper-vue3.md +152 -0
  135. package/skills/vue-debug-guides/reference/transition-js-hooks-done-callback.md +251 -0
  136. package/skills/vue-debug-guides/reference/transition-nested-duration.md +182 -0
  137. package/skills/vue-debug-guides/reference/transition-reusable-scoped-style.md +245 -0
  138. package/skills/vue-debug-guides/reference/transition-router-view-appear.md +193 -0
  139. package/skills/vue-debug-guides/reference/transition-type-when-mixed.md +172 -0
  140. package/skills/vue-debug-guides/reference/transition-unmount-hook-timing.md +149 -0
  141. package/skills/vue-debug-guides/reference/ts-defineprops-boolean-default-false.md +225 -0
  142. package/skills/vue-debug-guides/reference/ts-defineprops-imported-types-limitations.md +281 -0
  143. package/skills/vue-debug-guides/reference/ts-event-handler-explicit-typing.md +213 -0
  144. package/skills/vue-debug-guides/reference/ts-reactive-no-generic-argument.md +196 -0
  145. package/skills/vue-debug-guides/reference/ts-shallowref-for-dynamic-components.md +218 -0
  146. package/skills/vue-debug-guides/reference/ts-template-ref-null-handling.md +249 -0
  147. package/skills/vue-debug-guides/reference/ts-template-type-casting.md +214 -0
  148. package/skills/vue-debug-guides/reference/ts-withdefaults-mutable-factory-function.md +171 -0
  149. package/skills/vue-debug-guides/reference/undeclared-emits-double-firing.md +195 -0
  150. package/skills/vue-debug-guides/reference/use-template-ref-vue35.md +158 -0
  151. package/skills/vue-debug-guides/reference/v-else-must-follow-v-if.md +136 -0
  152. package/skills/vue-debug-guides/reference/v-for-component-props.md +95 -0
  153. package/skills/vue-debug-guides/reference/v-for-computed-reverse-sort.md +86 -0
  154. package/skills/vue-debug-guides/reference/v-for-key-attribute.md +90 -0
  155. package/skills/vue-debug-guides/reference/v-for-range-starts-at-one.md +66 -0
  156. package/skills/vue-debug-guides/reference/v-if-null-check-order.md +171 -0
  157. package/skills/vue-debug-guides/reference/v-model-ignores-html-attributes.md +83 -0
  158. package/skills/vue-debug-guides/reference/v-model-ime-composition.md +83 -0
  159. package/skills/vue-debug-guides/reference/v-model-number-modifier-behavior.md +124 -0
  160. package/skills/vue-debug-guides/reference/v-show-template-limitation.md +124 -0
  161. package/skills/vue-debug-guides/reference/watch-async-cleanup.md +180 -0
  162. package/skills/vue-debug-guides/reference/watch-async-creation-memory-leak.md +176 -0
  163. package/skills/vue-debug-guides/reference/watch-deep-same-object-reference.md +165 -0
  164. package/skills/vue-debug-guides/reference/watch-flush-timing.md +189 -0
  165. package/skills/vue-debug-guides/reference/watch-reactive-property-getter.md +108 -0
  166. package/skills/vue-debug-guides/reference/watcheffect-async-dependency-tracking.md +173 -0
  167. package/skills/vue-debug-guides/reference/watcheffect-flush-post-for-refs.md +176 -0
  168. package/skills/vue-jsx-best-practices/SKILL.md +12 -0
  169. package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
  170. package/skills/vue-options-api-best-practices/SKILL.md +23 -0
  171. package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
  172. package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
  173. package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
  174. package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
  175. package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
  176. package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
  177. package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
  178. package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
  179. package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
  180. package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
  181. package/skills/vue-pinia-best-practices/SKILL.md +21 -0
  182. package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
  183. package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
  184. package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
  185. package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
  186. package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
  187. package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
  188. package/skills/vue-router-best-practices/SKILL.md +23 -0
  189. package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
  190. package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
  191. package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
  192. package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
  193. package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
  194. package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
  195. package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
  196. package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
  197. package/skills/vue-testing-best-practices/SKILL.md +29 -0
  198. package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
  199. package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
  200. package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
  201. package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
  202. package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
  203. package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
  204. package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
  205. package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
  206. package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
  207. package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
  208. package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
@@ -0,0 +1,281 @@
1
+ ---
2
+ title: Imported Types Have Limitations in defineProps
3
+ impact: MEDIUM
4
+ impactDescription: Complex imported types like conditional types can cause compiler errors in defineProps
5
+ type: gotcha
6
+ tags: [vue3, typescript, defineProps, imported-types, vue3.3]
7
+ ---
8
+
9
+ # Imported Types Have Limitations in defineProps
10
+
11
+ **Impact: MEDIUM** - While Vue 3.3+ supports imported types in `defineProps<>()`, certain complex types are not fully supported. Conditional types, mapped types that require full type analysis, and global ambient types can cause "Unresolvable type reference" errors.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Understand which type patterns are supported vs unsupported
16
+ - [ ] Keep prop type definitions simple and explicit
17
+ - [ ] Move complex type logic outside of defineProps
18
+ - [ ] Export interfaces explicitly rather than using global declarations
19
+
20
+ ## Supported Patterns (Vue 3.3+)
21
+
22
+ ```typescript
23
+ // types/user.ts
24
+ export interface User {
25
+ id: string
26
+ name: string
27
+ email?: string
28
+ }
29
+
30
+ export interface ListProps<T> {
31
+ items: T[]
32
+ selectedItem?: T
33
+ }
34
+
35
+ export type Status = 'pending' | 'active' | 'completed'
36
+ ```
37
+
38
+ ```vue
39
+ <script setup lang="ts">
40
+ import type { User, Status } from '@/types/user'
41
+
42
+ // WORKS: Simple imported interface
43
+ defineProps<{
44
+ user: User
45
+ }>()
46
+
47
+ // WORKS: Imported union type
48
+ defineProps<{
49
+ status: Status
50
+ }>()
51
+
52
+ // WORKS: Direct imported interface
53
+ defineProps<User>()
54
+ </script>
55
+ ```
56
+
57
+ ## Unsupported Patterns
58
+
59
+ ### Conditional Types for Entire Props Object
60
+
61
+ ```typescript
62
+ // types/conditional.ts
63
+ export type ConditionalProps<T> = T extends string
64
+ ? { value: string; onChange: (v: string) => void }
65
+ : { value: number; onChange: (v: number) => void }
66
+ ```
67
+
68
+ ```vue
69
+ <script setup lang="ts">
70
+ import type { ConditionalProps } from '@/types/conditional'
71
+
72
+ // ERROR: Conditional types not supported for entire props object
73
+ defineProps<ConditionalProps<string>>()
74
+ </script>
75
+ ```
76
+
77
+ **Workaround:**
78
+ ```vue
79
+ <script setup lang="ts">
80
+ // Define the resolved type directly
81
+ interface StringProps {
82
+ value: string
83
+ onChange: (v: string) => void
84
+ }
85
+
86
+ defineProps<StringProps>()
87
+ </script>
88
+ ```
89
+
90
+ ### Conditional Types for Individual Props ARE Supported
91
+
92
+ ```vue
93
+ <script setup lang="ts">
94
+ // This WORKS - conditional type on individual prop
95
+ interface Props {
96
+ value: SomeType extends string ? string : number // OK
97
+ }
98
+
99
+ defineProps<Props>()
100
+ </script>
101
+ ```
102
+
103
+ ### Global Ambient Types
104
+
105
+ ```typescript
106
+ // global.d.ts (ambient declaration without export)
107
+ interface GlobalUser {
108
+ id: string
109
+ name: string
110
+ }
111
+
112
+ // No export statement - this is an ambient declaration
113
+ ```
114
+
115
+ ```vue
116
+ <script setup lang="ts">
117
+ // ERROR: "Unresolvable type reference"
118
+ defineProps<{
119
+ user: GlobalUser // Can't resolve ambient global type
120
+ }>()
121
+ </script>
122
+ ```
123
+
124
+ **Workaround:**
125
+ ```typescript
126
+ // types/user.ts - Use explicit export
127
+ export interface GlobalUser {
128
+ id: string
129
+ name: string
130
+ }
131
+ ```
132
+
133
+ ```vue
134
+ <script setup lang="ts">
135
+ import type { GlobalUser } from '@/types/user'
136
+
137
+ // WORKS: Explicitly imported
138
+ defineProps<{
139
+ user: GlobalUser
140
+ }>()
141
+ </script>
142
+ ```
143
+
144
+ ### Complex Mapped Types
145
+
146
+ ```typescript
147
+ // types/complex.ts
148
+ export type DeepReadonly<T> = {
149
+ readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]
150
+ }
151
+
152
+ export interface User {
153
+ id: string
154
+ profile: { name: string }
155
+ }
156
+ ```
157
+
158
+ ```vue
159
+ <script setup lang="ts">
160
+ import type { DeepReadonly, User } from '@/types/complex'
161
+
162
+ // May fail or produce incorrect types
163
+ defineProps<{
164
+ user: DeepReadonly<User>
165
+ }>()
166
+ </script>
167
+ ```
168
+
169
+ **Workaround:**
170
+ ```typescript
171
+ // Resolve the type explicitly
172
+ export interface ReadonlyUser {
173
+ readonly id: string
174
+ readonly profile: { readonly name: string }
175
+ }
176
+ ```
177
+
178
+ ### Union of Imported Interfaces
179
+
180
+ ```typescript
181
+ // types/forms.ts
182
+ export interface TextInput { type: 'text'; value: string }
183
+ export interface NumberInput { type: 'number'; value: number }
184
+ ```
185
+
186
+ ```vue
187
+ <script setup lang="ts">
188
+ import type { TextInput, NumberInput } from '@/types/forms'
189
+
190
+ // Can cause issues in some Vue versions
191
+ defineProps<{
192
+ input: TextInput | NumberInput
193
+ }>()
194
+ </script>
195
+ ```
196
+
197
+ **Workaround:**
198
+ ```typescript
199
+ // Define the union in the types file
200
+ export type AnyInput = TextInput | NumberInput
201
+ ```
202
+
203
+ ```vue
204
+ <script setup lang="ts">
205
+ import type { AnyInput } from '@/types/forms'
206
+
207
+ defineProps<{
208
+ input: AnyInput
209
+ }>()
210
+ </script>
211
+ ```
212
+
213
+ ## Best Practices
214
+
215
+ ### Keep Props Types Simple
216
+
217
+ ```typescript
218
+ // GOOD: Simple, explicit interface
219
+ export interface ButtonProps {
220
+ variant: 'primary' | 'secondary' | 'danger'
221
+ size: 'sm' | 'md' | 'lg'
222
+ disabled?: boolean
223
+ loading?: boolean
224
+ }
225
+
226
+ // AVOID: Over-engineered generic types
227
+ export type ButtonProps<V extends string, S extends string> = {
228
+ variant: V
229
+ size: S
230
+ // ...complex type gymnastics
231
+ }
232
+ ```
233
+
234
+ ### Resolve Types Before Export
235
+
236
+ ```typescript
237
+ // Instead of exporting generic utilities
238
+ // export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
239
+
240
+ // Export the resolved type
241
+ export interface CreateUserProps {
242
+ name: string
243
+ email: string
244
+ age?: number // Made optional
245
+ role?: 'admin' | 'user' // Made optional
246
+ }
247
+ ```
248
+
249
+ ### Use Dual Script Blocks for Complex Cases
250
+
251
+ ```vue
252
+ <script lang="ts">
253
+ // Regular script block for complex type definitions
254
+ import type { ComplexType } from '@/types'
255
+
256
+ // Resolve the type here
257
+ type ResolvedProps = ComplexType extends SomeCondition
258
+ ? { a: string }
259
+ : { b: number }
260
+ </script>
261
+
262
+ <script setup lang="ts">
263
+ // Use the resolved type
264
+ defineProps<ResolvedProps>()
265
+ </script>
266
+ ```
267
+
268
+ ## Version-Specific Behavior
269
+
270
+ | Vue Version | Imported Types | Complex Types |
271
+ |-------------|---------------|---------------|
272
+ | 3.2 | Not supported | Not supported |
273
+ | 3.3 | Supported | Limited |
274
+ | 3.4+ | Supported | Better support |
275
+
276
+ Always check the Vue changelog for updates to type support in defineProps.
277
+
278
+ ## Reference
279
+ - [Vue.js TypeScript with Composition API](https://vuejs.org/guide/typescript/composition-api.html)
280
+ - [GitHub Issue: defineProps with imported interfaces](https://github.com/vuejs/core/issues/8612)
281
+ - [GitHub Issue: Union types in defineProps](https://github.com/vuejs/core/issues/5804)
@@ -0,0 +1,213 @@
1
+ ---
2
+ title: Always Explicitly Type Event Handlers
3
+ impact: MEDIUM
4
+ impactDescription: Without explicit typing, event parameters have implicit 'any' type causing TypeScript errors in strict mode
5
+ type: gotcha
6
+ tags: [vue3, typescript, events, dom-events, composition-api]
7
+ ---
8
+
9
+ # Always Explicitly Type Event Handlers
10
+
11
+ **Impact: MEDIUM** - Native DOM event handlers in Vue components have implicit `any` type for the `event` parameter. In TypeScript strict mode, this causes errors. You must explicitly type event parameters and use type assertions for `event.target`.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Always type the `event` parameter explicitly (e.g., `Event`, `MouseEvent`)
16
+ - [ ] Use type assertions when accessing element-specific properties
17
+ - [ ] Consider using inline handlers for simple cases
18
+ - [ ] Be aware of Vue's synthetic event system
19
+
20
+ ## The Problem
21
+
22
+ ```vue
23
+ <script setup lang="ts">
24
+ // WRONG: event has implicit 'any' type
25
+ function handleChange(event) { // Error in strict mode!
26
+ console.log(event.target.value) // Also error: target might be null
27
+ }
28
+
29
+ // WRONG: Missing type assertion for element access
30
+ function handleInput(event: Event) {
31
+ console.log(event.target.value) // Error: 'value' doesn't exist on EventTarget
32
+ }
33
+ </script>
34
+
35
+ <template>
36
+ <input @change="handleChange" @input="handleInput" />
37
+ </template>
38
+ ```
39
+
40
+ ## The Solution
41
+
42
+ ```vue
43
+ <script setup lang="ts">
44
+ // CORRECT: Explicit Event type + type assertion
45
+ function handleChange(event: Event) {
46
+ const target = event.target as HTMLInputElement
47
+ console.log(target.value)
48
+ }
49
+
50
+ // CORRECT: Specific event type when needed
51
+ function handleClick(event: MouseEvent) {
52
+ console.log(event.clientX, event.clientY)
53
+ }
54
+
55
+ function handleKeydown(event: KeyboardEvent) {
56
+ if (event.key === 'Enter') {
57
+ submitForm()
58
+ }
59
+ }
60
+
61
+ function handleSubmit(event: SubmitEvent) {
62
+ event.preventDefault()
63
+ const formData = new FormData(event.target as HTMLFormElement)
64
+ }
65
+ </script>
66
+
67
+ <template>
68
+ <input @change="handleChange" />
69
+ <button @click="handleClick">Click</button>
70
+ <input @keydown="handleKeydown" />
71
+ <form @submit="handleSubmit">...</form>
72
+ </template>
73
+ ```
74
+
75
+ ## Common Event Types
76
+
77
+ | Event | Type | Common Properties |
78
+ |-------|------|-------------------|
79
+ | click, dblclick | `MouseEvent` | clientX, clientY, button |
80
+ | keydown, keyup, keypress | `KeyboardEvent` | key, code, ctrlKey, shiftKey |
81
+ | input, change | `Event` | target (needs assertion) |
82
+ | focus, blur | `FocusEvent` | relatedTarget |
83
+ | submit | `SubmitEvent` | submitter |
84
+ | drag, dragstart, drop | `DragEvent` | dataTransfer |
85
+ | wheel, scroll | `WheelEvent` | deltaX, deltaY |
86
+ | touch events | `TouchEvent` | touches, changedTouches |
87
+
88
+ ## Element-Specific Type Assertions
89
+
90
+ ```vue
91
+ <script setup lang="ts">
92
+ // HTMLInputElement for text, number, checkbox, radio inputs
93
+ function handleTextInput(event: Event) {
94
+ const input = event.target as HTMLInputElement
95
+ console.log(input.value, input.checked)
96
+ }
97
+
98
+ // HTMLSelectElement for select dropdowns
99
+ function handleSelect(event: Event) {
100
+ const select = event.target as HTMLSelectElement
101
+ console.log(select.value, select.selectedIndex)
102
+ }
103
+
104
+ // HTMLTextAreaElement for textareas
105
+ function handleTextarea(event: Event) {
106
+ const textarea = event.target as HTMLTextAreaElement
107
+ console.log(textarea.value, textarea.selectionStart)
108
+ }
109
+
110
+ // HTMLFormElement for forms
111
+ function handleFormSubmit(event: SubmitEvent) {
112
+ event.preventDefault()
113
+ const form = event.target as HTMLFormElement
114
+ const formData = new FormData(form)
115
+ }
116
+ </script>
117
+ ```
118
+
119
+ ## Inline Event Handler Pattern
120
+
121
+ For simple cases, inline handlers with type annotations work well:
122
+
123
+ ```vue
124
+ <template>
125
+ <!-- Inline with type assertion -->
126
+ <input
127
+ @input="(event: Event) => {
128
+ const input = event.target as HTMLInputElement
129
+ searchQuery = input.value
130
+ }"
131
+ />
132
+
133
+ <!-- Or with $event cast -->
134
+ <input @input="searchQuery = ($event.target as HTMLInputElement).value" />
135
+ </template>
136
+ ```
137
+
138
+ ## Generic Handler Pattern
139
+
140
+ Create reusable typed handlers:
141
+
142
+ ```typescript
143
+ // utils/events.ts
144
+ export function getInputValue(event: Event): string {
145
+ return (event.target as HTMLInputElement).value
146
+ }
147
+
148
+ export function getSelectValue(event: Event): string {
149
+ return (event.target as HTMLSelectElement).value
150
+ }
151
+
152
+ export function getCheckboxChecked(event: Event): boolean {
153
+ return (event.target as HTMLInputElement).checked
154
+ }
155
+ ```
156
+
157
+ ```vue
158
+ <script setup lang="ts">
159
+ import { getInputValue, getCheckboxChecked } from '@/utils/events'
160
+
161
+ const name = ref('')
162
+ const agreed = ref(false)
163
+ </script>
164
+
165
+ <template>
166
+ <input @input="e => name = getInputValue(e)" />
167
+ <input type="checkbox" @change="e => agreed = getCheckboxChecked(e)" />
168
+ </template>
169
+ ```
170
+
171
+ ## Vue Component Events
172
+
173
+ For Vue component events (not DOM events), use `defineEmits` for type safety:
174
+
175
+ ```vue
176
+ <script setup lang="ts">
177
+ const emit = defineEmits<{
178
+ 'custom-event': [data: { id: number; name: string }]
179
+ }>()
180
+
181
+ // Handler for child component event
182
+ function handleChildEvent(data: { id: number; name: string }) {
183
+ console.log(data.id, data.name)
184
+ }
185
+ </script>
186
+
187
+ <template>
188
+ <!-- Custom component event - properly typed -->
189
+ <ChildComponent @custom-event="handleChildEvent" />
190
+ </template>
191
+ ```
192
+
193
+ ## Avoiding currentTarget vs target Confusion
194
+
195
+ ```typescript
196
+ function handleClick(event: MouseEvent) {
197
+ // target: The element that triggered the event (could be a child)
198
+ const target = event.target as HTMLElement
199
+
200
+ // currentTarget: The element the listener is attached to
201
+ const currentTarget = event.currentTarget as HTMLButtonElement
202
+
203
+ // Be explicit about which you need
204
+ if (target.tagName === 'SPAN') {
205
+ // Clicked on span inside button
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## Reference
211
+ - [Vue.js TypeScript with Composition API - Event Handlers](https://vuejs.org/guide/typescript/composition-api.html#typing-event-handlers)
212
+ - [MDN Event Reference](https://developer.mozilla.org/en-US/docs/Web/Events)
213
+ - [TypeScript DOM Types](https://github.com/microsoft/TypeScript/blob/main/lib/lib.dom.d.ts)
@@ -0,0 +1,196 @@
1
+ ---
2
+ title: Do Not Use Generic Argument with reactive()
3
+ impact: MEDIUM
4
+ impactDescription: The generic argument type differs from the actual return type due to ref unwrapping, causing type mismatches
5
+ type: gotcha
6
+ tags: [vue3, typescript, reactive, ref-unwrapping, composition-api]
7
+ ---
8
+
9
+ # Do Not Use Generic Argument with reactive()
10
+
11
+ **Impact: MEDIUM** - It is NOT recommended to use the generic argument of `reactive()` because the returned type, which handles nested ref unwrapping, is different from the generic argument type. Use interface annotation on the variable instead.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Use type annotation on the variable, not generic argument
16
+ - [ ] Understand that `reactive()` unwraps nested refs
17
+ - [ ] For generic composables, use `shallowRef` or explicit `Ref<T>` typing
18
+ - [ ] Prefer `ref()` for simple values to avoid these issues
19
+
20
+ ## The Problem
21
+
22
+ ```vue
23
+ <script setup lang="ts">
24
+ import { reactive, ref } from 'vue'
25
+
26
+ interface Book {
27
+ title: string
28
+ year: number
29
+ author: Ref<string> // Nested ref
30
+ }
31
+
32
+ // WRONG: Generic argument doesn't account for ref unwrapping
33
+ const book = reactive<Book>({
34
+ title: 'Vue 3 Guide',
35
+ year: 2024,
36
+ author: ref('John Doe')
37
+ })
38
+
39
+ // TypeScript thinks book.author is Ref<string>
40
+ // But at runtime, it's unwrapped to just string!
41
+ book.author.value // TypeScript: OK, Runtime: ERROR (author is a string, not a ref)
42
+ </script>
43
+ ```
44
+
45
+ ## The Solution: Interface Annotation
46
+
47
+ ```vue
48
+ <script setup lang="ts">
49
+ import { reactive, ref } from 'vue'
50
+
51
+ interface Book {
52
+ title: string
53
+ year?: number
54
+ }
55
+
56
+ // CORRECT: Annotate the variable, not the generic
57
+ const book: Book = reactive({
58
+ title: 'Vue 3 Guide'
59
+ })
60
+
61
+ book.title = 'New Title' // TypeScript knows this is string
62
+ book.year = 2024 // TypeScript knows this is number | undefined
63
+ </script>
64
+ ```
65
+
66
+ ## Why This Happens
67
+
68
+ When you use `reactive()`, Vue automatically unwraps any nested refs:
69
+
70
+ ```typescript
71
+ import { reactive, ref, Ref } from 'vue'
72
+
73
+ const name = ref('John')
74
+ const state = reactive({
75
+ name: name // This is a Ref<string>
76
+ })
77
+
78
+ // At runtime, state.name is 'John' (string), NOT a Ref
79
+ console.log(state.name) // 'John' (not ref object)
80
+ console.log(state.name.value) // Runtime error: .value doesn't exist
81
+
82
+ // The ACTUAL return type is different from what you'd expect
83
+ // reactive<{ name: Ref<string> }>() does NOT return { name: Ref<string> }
84
+ // It returns { name: string } due to automatic unwrapping
85
+ ```
86
+
87
+ ## Correct Patterns
88
+
89
+ ### Pattern 1: Simple Interface Annotation
90
+
91
+ ```vue
92
+ <script setup lang="ts">
93
+ interface FormState {
94
+ name: string
95
+ email: string
96
+ age: number
97
+ }
98
+
99
+ const form: FormState = reactive({
100
+ name: '',
101
+ email: '',
102
+ age: 0
103
+ })
104
+ </script>
105
+ ```
106
+
107
+ ### Pattern 2: Partial for Optional Fields
108
+
109
+ ```vue
110
+ <script setup lang="ts">
111
+ interface User {
112
+ id: string
113
+ name: string
114
+ email: string
115
+ }
116
+
117
+ // Start with partial data
118
+ const user: Partial<User> = reactive({})
119
+
120
+ // Fill in later
121
+ user.id = '123'
122
+ user.name = 'John'
123
+ </script>
124
+ ```
125
+
126
+ ### Pattern 3: Use ref() Instead
127
+
128
+ For simpler cases, prefer `ref()` which has more predictable typing:
129
+
130
+ ```vue
131
+ <script setup lang="ts">
132
+ interface User {
133
+ id: string
134
+ name: string
135
+ }
136
+
137
+ // ref() works well with generics
138
+ const user = ref<User>({
139
+ id: '1',
140
+ name: 'John'
141
+ })
142
+
143
+ // Access with .value - clear and predictable
144
+ user.value.name = 'Jane'
145
+ </script>
146
+ ```
147
+
148
+ ## Generic Composables: Use Ref<T> or shallowRef
149
+
150
+ When working with generic type parameters in composables:
151
+
152
+ ```typescript
153
+ // PROBLEM: Generic T with ref() causes UnwrapRef issues
154
+ function useBroken<T>(initial: T) {
155
+ const state = ref(initial) // Type becomes Ref<UnwrapRef<T>>
156
+ state.value = initial // Error: T is not assignable to UnwrapRef<T>
157
+ return state
158
+ }
159
+
160
+ // SOLUTION 1: Use explicit Ref<T> type
161
+ function useFixed1<T>(initial: T) {
162
+ const state: Ref<T> = ref(initial) as Ref<T>
163
+ return state
164
+ }
165
+
166
+ // SOLUTION 2: Use shallowRef (no unwrapping)
167
+ function useFixed2<T>(initial: T) {
168
+ const state = shallowRef(initial) // Properly typed as ShallowRef<T>
169
+ return state
170
+ }
171
+ ```
172
+
173
+ ## When Generic Argument IS Safe
174
+
175
+ For simple non-ref values without nested reactivity, the generic is safe:
176
+
177
+ ```typescript
178
+ // Safe: no nested refs
179
+ const state = reactive<{ count: number; name: string }>({
180
+ count: 0,
181
+ name: ''
182
+ })
183
+
184
+ // Also safe: explicit simple types
185
+ const list = reactive<string[]>([])
186
+ const map = reactive<Map<string, number>>(new Map())
187
+ ```
188
+
189
+ The issue only arises when:
190
+ 1. You have nested Ref types in your interface
191
+ 2. You're using generic type parameters that might contain refs
192
+
193
+ ## Reference
194
+ - [Vue.js TypeScript with Composition API - Typing reactive()](https://vuejs.org/guide/typescript/composition-api.html#typing-reactive)
195
+ - [GitHub Issue: ref with generic type](https://github.com/vuejs/core/discussions/9564)
196
+ - [Vue TypeScript Caveats Gist](https://gist.github.com/LinusBorg/e041ff635994b50b7cec9383c3a067f1)