@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.
- package/README.md +63 -0
- package/index.mjs +139 -0
- package/package.json +34 -0
- package/skills/create-adaptable-composable/SKILL.md +76 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +350 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +346 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-debug-guides/SKILL.md +205 -0
- package/skills/vue-debug-guides/reference/animation-key-for-rerender.md +160 -0
- package/skills/vue-debug-guides/reference/animation-transitiongroup-performance.md +241 -0
- package/skills/vue-debug-guides/reference/async-component-error-handling.md +115 -0
- package/skills/vue-debug-guides/reference/async-component-keepalive-ref-issue.md +112 -0
- package/skills/vue-debug-guides/reference/async-component-suspense-control.md +84 -0
- package/skills/vue-debug-guides/reference/async-component-vue-router.md +109 -0
- package/skills/vue-debug-guides/reference/attrs-event-listener-merging.md +205 -0
- package/skills/vue-debug-guides/reference/checkbox-true-false-value-form-submission.md +118 -0
- package/skills/vue-debug-guides/reference/cleanup-side-effects.md +172 -0
- package/skills/vue-debug-guides/reference/click-events-on-components.md +180 -0
- package/skills/vue-debug-guides/reference/component-naming-conflicts.md +159 -0
- package/skills/vue-debug-guides/reference/component-ref-requires-defineexpose.md +176 -0
- package/skills/vue-debug-guides/reference/composable-avoid-hidden-side-effects.md +208 -0
- package/skills/vue-debug-guides/reference/composable-call-location-restrictions.md +141 -0
- package/skills/vue-debug-guides/reference/composable-naming-return-pattern.md +139 -0
- package/skills/vue-debug-guides/reference/composable-tovalue-inside-watcheffect.md +182 -0
- package/skills/vue-debug-guides/reference/composition-api-not-functional-programming.md +120 -0
- package/skills/vue-debug-guides/reference/composition-api-script-setup-async-context.md +203 -0
- package/skills/vue-debug-guides/reference/composition-api-vs-react-hooks-differences.md +156 -0
- package/skills/vue-debug-guides/reference/computed-array-mutation.md +148 -0
- package/skills/vue-debug-guides/reference/computed-conditional-dependencies.md +147 -0
- package/skills/vue-debug-guides/reference/computed-no-parameters.md +159 -0
- package/skills/vue-debug-guides/reference/computed-no-side-effects.md +107 -0
- package/skills/vue-debug-guides/reference/computed-return-value-readonly.md +160 -0
- package/skills/vue-debug-guides/reference/configure-app-before-mount.md +89 -0
- package/skills/vue-debug-guides/reference/declare-emits-for-documentation.md +212 -0
- package/skills/vue-debug-guides/reference/define-expose-before-await.md +192 -0
- package/skills/vue-debug-guides/reference/define-model-default-value-sync.md +139 -0
- package/skills/vue-debug-guides/reference/defineEmits-must-be-top-level.md +164 -0
- package/skills/vue-debug-guides/reference/defineEmits-no-runtime-and-type-mixed.md +170 -0
- package/skills/vue-debug-guides/reference/definemodel-object-mutation-no-emit.md +148 -0
- package/skills/vue-debug-guides/reference/dom-update-timing-nexttick.md +90 -0
- package/skills/vue-debug-guides/reference/dynamic-argument-constraints.md +146 -0
- package/skills/vue-debug-guides/reference/dynamic-component-registration-vite.md +147 -0
- package/skills/vue-debug-guides/reference/event-modifier-order-matters.md +101 -0
- package/skills/vue-debug-guides/reference/exact-modifier-for-precise-shortcuts.md +155 -0
- package/skills/vue-debug-guides/reference/fallthrough-attrs-overwrite-vue3.md +159 -0
- package/skills/vue-debug-guides/reference/in-dom-template-parsing-caveats.md +149 -0
- package/skills/vue-debug-guides/reference/inheritattrs-false-for-wrapper-components.md +230 -0
- package/skills/vue-debug-guides/reference/keepalive-router-nested-double-mount.md +222 -0
- package/skills/vue-debug-guides/reference/keepalive-transition-memory-leak.md +144 -0
- package/skills/vue-debug-guides/reference/keyup-modifier-timing.md +137 -0
- package/skills/vue-debug-guides/reference/lifecycle-dom-access-timing.md +216 -0
- package/skills/vue-debug-guides/reference/lifecycle-hooks-synchronous-registration.md +156 -0
- package/skills/vue-debug-guides/reference/lifecycle-ssr-awareness.md +184 -0
- package/skills/vue-debug-guides/reference/local-components-not-in-descendants.md +151 -0
- package/skills/vue-debug-guides/reference/mount-return-value.md +88 -0
- package/skills/vue-debug-guides/reference/multi-root-component-class-attrs.md +93 -0
- package/skills/vue-debug-guides/reference/native-event-collision-with-emits.md +162 -0
- package/skills/vue-debug-guides/reference/no-passive-with-prevent.md +141 -0
- package/skills/vue-debug-guides/reference/no-v-if-with-v-for.md +136 -0
- package/skills/vue-debug-guides/reference/perf-computed-object-stability.md +157 -0
- package/skills/vue-debug-guides/reference/perf-props-stability-update-optimization.md +140 -0
- package/skills/vue-debug-guides/reference/plugin-global-properties-sparingly.md +109 -0
- package/skills/vue-debug-guides/reference/plugin-install-before-mount.md +124 -0
- package/skills/vue-debug-guides/reference/plugin-prefer-provide-inject-over-global-properties.md +120 -0
- package/skills/vue-debug-guides/reference/plugin-typescript-type-augmentation.md +157 -0
- package/skills/vue-debug-guides/reference/prop-defineprops-scope-limitation.md +161 -0
- package/skills/vue-debug-guides/reference/provide-inject-debugging-challenges.md +203 -0
- package/skills/vue-debug-guides/reference/provide-inject-default-value-factory.md +244 -0
- package/skills/vue-debug-guides/reference/provide-inject-reactivity-not-automatic.md +226 -0
- package/skills/vue-debug-guides/reference/provide-inject-synchronous-setup.md +235 -0
- package/skills/vue-debug-guides/reference/reactive-destructuring.md +89 -0
- package/skills/vue-debug-guides/reference/reactivity-debugging-hooks.md +132 -0
- package/skills/vue-debug-guides/reference/reactivity-markraw-for-non-reactive.md +149 -0
- package/skills/vue-debug-guides/reference/reactivity-proxy-identity-hazard.md +96 -0
- package/skills/vue-debug-guides/reference/reactivity-same-tick-batching.md +166 -0
- package/skills/vue-debug-guides/reference/ref-value-access.md +61 -0
- package/skills/vue-debug-guides/reference/refs-in-collections-need-value.md +81 -0
- package/skills/vue-debug-guides/reference/render-function-avoid-internal-vnode-properties.md +151 -0
- package/skills/vue-debug-guides/reference/render-function-vnodes-must-be-unique.md +133 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-h-import-vue3.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-return-from-setup.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-slots-as-functions.md +168 -0
- package/skills/vue-debug-guides/reference/rendering-resolve-component-for-string-names.md +231 -0
- package/skills/vue-debug-guides/reference/select-initial-value-ios-bug.md +91 -0
- package/skills/vue-debug-guides/reference/self-referencing-component-name.md +157 -0
- package/skills/vue-debug-guides/reference/sfc-named-exports-forbidden.md +184 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-child-component-styling.md +156 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-dynamic-content.md +193 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-slot-content.md +242 -0
- package/skills/vue-debug-guides/reference/sfc-script-setup-reactivity.md +195 -0
- package/skills/vue-debug-guides/reference/slot-forwarding-to-child-components.md +143 -0
- package/skills/vue-debug-guides/reference/slot-implicit-default-content.md +155 -0
- package/skills/vue-debug-guides/reference/slot-name-reserved-prop.md +109 -0
- package/skills/vue-debug-guides/reference/slot-named-scoped-explicit-default.md +95 -0
- package/skills/vue-debug-guides/reference/slot-render-scope-parent-only.md +135 -0
- package/skills/vue-debug-guides/reference/slot-v-slot-on-components-or-templates-only.md +122 -0
- package/skills/vue-debug-guides/reference/ssr-hydration-mismatch-causes.md +280 -0
- package/skills/vue-debug-guides/reference/ssr-platform-specific-apis.md +256 -0
- package/skills/vue-debug-guides/reference/state-ssr-cross-request-pollution.md +276 -0
- package/skills/vue-debug-guides/reference/suspense-no-builtin-error-handling.md +127 -0
- package/skills/vue-debug-guides/reference/suspense-ssr-hydration-issues.md +159 -0
- package/skills/vue-debug-guides/reference/tailwind-dynamic-class-generation.md +144 -0
- package/skills/vue-debug-guides/reference/teleport-scoped-styles-limitation.md +191 -0
- package/skills/vue-debug-guides/reference/teleport-ssr-hydration.md +152 -0
- package/skills/vue-debug-guides/reference/teleport-target-must-exist.md +113 -0
- package/skills/vue-debug-guides/reference/template-expressions-restrictions.md +114 -0
- package/skills/vue-debug-guides/reference/template-functions-no-side-effects.md +187 -0
- package/skills/vue-debug-guides/reference/template-ref-null-with-v-if.md +123 -0
- package/skills/vue-debug-guides/reference/template-ref-unwrapping-top-level.md +104 -0
- package/skills/vue-debug-guides/reference/template-ref-v-for-order.md +172 -0
- package/skills/vue-debug-guides/reference/textarea-no-interpolation.md +72 -0
- package/skills/vue-debug-guides/reference/transition-group-flip-inline-elements.md +152 -0
- package/skills/vue-debug-guides/reference/transition-group-move-animation-position-absolute.md +130 -0
- package/skills/vue-debug-guides/reference/transition-group-no-default-wrapper-vue3.md +152 -0
- package/skills/vue-debug-guides/reference/transition-js-hooks-done-callback.md +251 -0
- package/skills/vue-debug-guides/reference/transition-nested-duration.md +182 -0
- package/skills/vue-debug-guides/reference/transition-reusable-scoped-style.md +245 -0
- package/skills/vue-debug-guides/reference/transition-router-view-appear.md +193 -0
- package/skills/vue-debug-guides/reference/transition-type-when-mixed.md +172 -0
- package/skills/vue-debug-guides/reference/transition-unmount-hook-timing.md +149 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-boolean-default-false.md +225 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-imported-types-limitations.md +281 -0
- package/skills/vue-debug-guides/reference/ts-event-handler-explicit-typing.md +213 -0
- package/skills/vue-debug-guides/reference/ts-reactive-no-generic-argument.md +196 -0
- package/skills/vue-debug-guides/reference/ts-shallowref-for-dynamic-components.md +218 -0
- package/skills/vue-debug-guides/reference/ts-template-ref-null-handling.md +249 -0
- package/skills/vue-debug-guides/reference/ts-template-type-casting.md +214 -0
- package/skills/vue-debug-guides/reference/ts-withdefaults-mutable-factory-function.md +171 -0
- package/skills/vue-debug-guides/reference/undeclared-emits-double-firing.md +195 -0
- package/skills/vue-debug-guides/reference/use-template-ref-vue35.md +158 -0
- package/skills/vue-debug-guides/reference/v-else-must-follow-v-if.md +136 -0
- package/skills/vue-debug-guides/reference/v-for-component-props.md +95 -0
- package/skills/vue-debug-guides/reference/v-for-computed-reverse-sort.md +86 -0
- package/skills/vue-debug-guides/reference/v-for-key-attribute.md +90 -0
- package/skills/vue-debug-guides/reference/v-for-range-starts-at-one.md +66 -0
- package/skills/vue-debug-guides/reference/v-if-null-check-order.md +171 -0
- package/skills/vue-debug-guides/reference/v-model-ignores-html-attributes.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-ime-composition.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-number-modifier-behavior.md +124 -0
- package/skills/vue-debug-guides/reference/v-show-template-limitation.md +124 -0
- package/skills/vue-debug-guides/reference/watch-async-cleanup.md +180 -0
- package/skills/vue-debug-guides/reference/watch-async-creation-memory-leak.md +176 -0
- package/skills/vue-debug-guides/reference/watch-deep-same-object-reference.md +165 -0
- package/skills/vue-debug-guides/reference/watch-flush-timing.md +189 -0
- package/skills/vue-debug-guides/reference/watch-reactive-property-getter.md +108 -0
- package/skills/vue-debug-guides/reference/watcheffect-async-dependency-tracking.md +173 -0
- package/skills/vue-debug-guides/reference/watcheffect-flush-post-for-refs.md +176 -0
- package/skills/vue-jsx-best-practices/SKILL.md +12 -0
- package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
- package/skills/vue-options-api-best-practices/SKILL.md +23 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
- package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
- package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
- package/skills/vue-pinia-best-practices/SKILL.md +21 -0
- package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
- package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
- package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
- package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
- package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
- package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Arrow Functions for Prop Validators in TypeScript < 4.7
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Regular functions in prop validators can break type inference for the entire component in TypeScript versions before 4.7
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, typescript, options-api, props, type-inference, defineComponent, legacy]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Use Arrow Functions for Prop Validators in TypeScript < 4.7
|
|
10
|
+
|
|
11
|
+
> **LEGACY CONCERN:** This issue was fixed in TypeScript 4.7 (released May 2022). Most modern projects using TypeScript 4.7+ do not need this workaround. If you're starting a new project or have upgraded TypeScript recently, you can safely use regular functions in prop validators. This rule is primarily relevant for legacy codebases still running TypeScript < 4.7.
|
|
12
|
+
|
|
13
|
+
**Impact: HIGH** - If your TypeScript version is less than 4.7, using regular functions for `validator` and `default` prop options can cause TypeScript to fail when inferring the type of `this`, which breaks type inference for the ENTIRE component, not just the prop.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Check your TypeScript version (`tsc --version`)
|
|
18
|
+
- [ ] If TypeScript < 4.7, use arrow functions for all `validator` and `default` prop options
|
|
19
|
+
- [ ] Consider upgrading to TypeScript 4.7+ to avoid this limitation entirely
|
|
20
|
+
|
|
21
|
+
## The Problem
|
|
22
|
+
|
|
23
|
+
TypeScript needs to infer the type of `this` inside regular functions. In Vue's Options API context, this inference can fail in versions before 4.7, causing cascading type inference failures.
|
|
24
|
+
|
|
25
|
+
**BAD - Can break type inference in TS < 4.7:**
|
|
26
|
+
```typescript
|
|
27
|
+
import { defineComponent, PropType } from 'vue'
|
|
28
|
+
|
|
29
|
+
interface Book {
|
|
30
|
+
title: string
|
|
31
|
+
author: string
|
|
32
|
+
year: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default defineComponent({
|
|
36
|
+
props: {
|
|
37
|
+
book: {
|
|
38
|
+
type: Object as PropType<Book>,
|
|
39
|
+
required: true,
|
|
40
|
+
// Regular function - causes inference issues in TS < 4.7
|
|
41
|
+
validator: function(book: Book) {
|
|
42
|
+
return book.title.length > 0
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
count: {
|
|
46
|
+
type: Number,
|
|
47
|
+
// Regular function - causes inference issues in TS < 4.7
|
|
48
|
+
default: function() {
|
|
49
|
+
return 0
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
// Type inference for computed, methods, etc. may break!
|
|
54
|
+
computed: {
|
|
55
|
+
bookTitle() {
|
|
56
|
+
// 'this' might be typed as 'any' due to broken inference
|
|
57
|
+
return this.book.title
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**GOOD - Use arrow functions:**
|
|
64
|
+
```typescript
|
|
65
|
+
import { defineComponent, PropType } from 'vue'
|
|
66
|
+
|
|
67
|
+
interface Book {
|
|
68
|
+
title: string
|
|
69
|
+
author: string
|
|
70
|
+
year: number
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default defineComponent({
|
|
74
|
+
props: {
|
|
75
|
+
book: {
|
|
76
|
+
type: Object as PropType<Book>,
|
|
77
|
+
required: true,
|
|
78
|
+
// Arrow function - safe for all TS versions
|
|
79
|
+
validator: (book: Book) => book.title.length > 0
|
|
80
|
+
},
|
|
81
|
+
count: {
|
|
82
|
+
type: Number,
|
|
83
|
+
// Arrow function - safe for all TS versions
|
|
84
|
+
default: () => 0
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
computed: {
|
|
88
|
+
bookTitle() {
|
|
89
|
+
// 'this' is properly typed
|
|
90
|
+
return this.book.title // Type: string
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Why Arrow Functions Work
|
|
97
|
+
|
|
98
|
+
Arrow functions don't have their own `this` binding, so TypeScript doesn't need to infer a `this` type for them. This avoids the type inference bug that affects regular functions in older TypeScript versions.
|
|
99
|
+
|
|
100
|
+
## For Object/Array Default Values
|
|
101
|
+
|
|
102
|
+
Arrow functions are especially important for object and array defaults (which Vue requires to be functions anyway):
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
props: {
|
|
106
|
+
config: {
|
|
107
|
+
type: Object as PropType<Config>,
|
|
108
|
+
// Must be a function, use arrow syntax
|
|
109
|
+
default: () => ({
|
|
110
|
+
enabled: true,
|
|
111
|
+
maxItems: 10
|
|
112
|
+
})
|
|
113
|
+
},
|
|
114
|
+
tags: {
|
|
115
|
+
type: Array as PropType<string[]>,
|
|
116
|
+
// Must be a function, use arrow syntax
|
|
117
|
+
default: () => []
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## When You Can Ignore This
|
|
123
|
+
|
|
124
|
+
- **TypeScript 4.7+**: This issue was fixed in TypeScript 4.7 (May 2022). If your project uses 4.7 or later, regular functions work fine. Since TypeScript 4.7 has been available for over 3 years, most actively maintained projects have already upgraded and do not need this workaround.
|
|
125
|
+
- **New projects**: If you're starting a new Vue project in 2024 or later, you'll almost certainly be using TypeScript 4.7+ by default and can ignore this rule entirely.
|
|
126
|
+
- **Arrow functions are still fine**: While not required in modern TypeScript, using arrow functions for validators and defaults remains a valid stylistic choice and causes no issues.
|
|
127
|
+
|
|
128
|
+
## Checking Your TypeScript Version
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Check installed TypeScript version
|
|
132
|
+
npx tsc --version
|
|
133
|
+
|
|
134
|
+
# Or check package.json
|
|
135
|
+
grep typescript package.json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Reference
|
|
139
|
+
|
|
140
|
+
- [Vue.js TypeScript with Options API](https://vuejs.org/guide/typescript/options-api.html#caveats)
|
|
141
|
+
- [TypeScript 4.7 Release Notes](https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/)
|
package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Explicitly Annotate Computed Property Return Types
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: While Vue usually infers computed types correctly, explicit annotations prevent circular inference issues and improve code documentation
|
|
5
|
+
type: best-practice
|
|
6
|
+
tags: [vue3, typescript, options-api, computed, type-inference]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Explicitly Annotate Computed Property Return Types
|
|
10
|
+
|
|
11
|
+
**Impact: LOW** - Vue can usually infer computed property return types automatically. However, explicit return type annotations prevent edge cases involving circular inference loops and serve as documentation for complex computed properties.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Consider adding return types to computed properties, especially complex ones
|
|
16
|
+
- [ ] Always add return types when TypeScript inference fails or shows incorrect types
|
|
17
|
+
- [ ] Add return types for writable computed properties (getter and setter)
|
|
18
|
+
|
|
19
|
+
## When Explicit Types Are Helpful
|
|
20
|
+
|
|
21
|
+
### 1. Complex Computed Properties
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { defineComponent } from 'vue'
|
|
25
|
+
|
|
26
|
+
interface CartItem {
|
|
27
|
+
id: number
|
|
28
|
+
name: string
|
|
29
|
+
price: number
|
|
30
|
+
quantity: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default defineComponent({
|
|
34
|
+
data() {
|
|
35
|
+
return {
|
|
36
|
+
items: [] as CartItem[],
|
|
37
|
+
discountPercent: 10
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
computed: {
|
|
41
|
+
// Without annotation - works but intent unclear
|
|
42
|
+
cartSummary() {
|
|
43
|
+
return {
|
|
44
|
+
subtotal: this.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
|
|
45
|
+
itemCount: this.items.reduce((sum, item) => sum + item.quantity, 0)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
// With annotation - clear intent, documented type
|
|
50
|
+
cartSummaryTyped(): { subtotal: number; itemCount: number; discount: number; total: number } {
|
|
51
|
+
const subtotal = this.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
|
|
52
|
+
const discount = subtotal * (this.discountPercent / 100)
|
|
53
|
+
return {
|
|
54
|
+
subtotal,
|
|
55
|
+
itemCount: this.items.reduce((sum, item) => sum + item.quantity, 0),
|
|
56
|
+
discount,
|
|
57
|
+
total: subtotal - discount
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Circular Inference Issues
|
|
65
|
+
|
|
66
|
+
Sometimes computed properties that reference each other can cause TypeScript inference to fail:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
export default defineComponent({
|
|
70
|
+
data() {
|
|
71
|
+
return {
|
|
72
|
+
firstName: 'John',
|
|
73
|
+
lastName: 'Doe'
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
computed: {
|
|
77
|
+
// Explicit return type breaks potential circular inference
|
|
78
|
+
fullName(): string {
|
|
79
|
+
return `${this.firstName} ${this.lastName}`
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
// References fullName - explicit type prevents inference issues
|
|
83
|
+
greeting(): string {
|
|
84
|
+
return `Hello, ${this.fullName}!`
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 3. Writable Computed Properties
|
|
91
|
+
|
|
92
|
+
Always annotate writable computed properties for clarity:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
export default defineComponent({
|
|
96
|
+
data() {
|
|
97
|
+
return {
|
|
98
|
+
firstName: 'John',
|
|
99
|
+
lastName: 'Doe'
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
computed: {
|
|
103
|
+
// Writable computed - explicit types for getter and setter
|
|
104
|
+
fullName: {
|
|
105
|
+
get(): string {
|
|
106
|
+
return `${this.firstName} ${this.lastName}`
|
|
107
|
+
},
|
|
108
|
+
set(newValue: string) {
|
|
109
|
+
const parts = newValue.split(' ')
|
|
110
|
+
this.firstName = parts[0] || ''
|
|
111
|
+
this.lastName = parts.slice(1).join(' ') || ''
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## When You Can Skip Explicit Types
|
|
119
|
+
|
|
120
|
+
Simple computed properties that TypeScript infers correctly:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
computed: {
|
|
124
|
+
// Simple string - TypeScript infers correctly
|
|
125
|
+
upperName() {
|
|
126
|
+
return this.name.toUpperCase()
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Simple boolean - TypeScript infers correctly
|
|
130
|
+
isEmpty() {
|
|
131
|
+
return this.items.length === 0
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
// Simple number - TypeScript infers correctly
|
|
135
|
+
totalCount() {
|
|
136
|
+
return this.items.length
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Interface for Complex Return Types
|
|
142
|
+
|
|
143
|
+
For complex computed return types, define interfaces:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
interface PaginationInfo {
|
|
147
|
+
currentPage: number
|
|
148
|
+
totalPages: number
|
|
149
|
+
hasNext: boolean
|
|
150
|
+
hasPrev: boolean
|
|
151
|
+
pageItems: Item[]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default defineComponent({
|
|
155
|
+
computed: {
|
|
156
|
+
pagination(): PaginationInfo {
|
|
157
|
+
const totalPages = Math.ceil(this.items.length / this.pageSize)
|
|
158
|
+
const start = (this.currentPage - 1) * this.pageSize
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
currentPage: this.currentPage,
|
|
162
|
+
totalPages,
|
|
163
|
+
hasNext: this.currentPage < totalPages,
|
|
164
|
+
hasPrev: this.currentPage > 1,
|
|
165
|
+
pageItems: this.items.slice(start, start + this.pageSize)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Debugging Type Inference
|
|
173
|
+
|
|
174
|
+
If you're unsure what TypeScript infers, hover over the computed property in your IDE, or add a temporary annotation to see errors:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
computed: {
|
|
178
|
+
// Hover over 'mystery' in IDE to see inferred type
|
|
179
|
+
mystery() {
|
|
180
|
+
return this.someComplexCalculation()
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
// Or add annotation to verify
|
|
184
|
+
mystery(): ExpectedType { // Error if inference differs
|
|
185
|
+
return this.someComplexCalculation()
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Reference
|
|
191
|
+
|
|
192
|
+
- [Vue.js TypeScript with Options API - Typing Computed Properties](https://vuejs.org/guide/typescript/options-api.html#typing-computed-properties)
|
package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use PropType for Complex Prop Types in Options API
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Vue's runtime prop types cannot express complex TypeScript types without PropType, leading to 'any' type inference
|
|
5
|
+
type: best-practice
|
|
6
|
+
tags: [vue3, typescript, options-api, props, PropType, type-safety]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Use PropType for Complex Prop Types in Options API
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - Vue's runtime `props` option only supports basic constructor functions (String, Number, etc.). To type complex props like interfaces, function signatures, or union types, you must use Vue's `PropType` utility type.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Import `PropType` from 'vue' for complex prop types
|
|
16
|
+
- [ ] Use `as PropType<YourType>` after `Object`, `Array`, or `Function`
|
|
17
|
+
- [ ] Define interfaces for your complex types
|
|
18
|
+
- [ ] Remember: PropType is purely for TypeScript - runtime validation only checks the constructor
|
|
19
|
+
|
|
20
|
+
## The Problem
|
|
21
|
+
|
|
22
|
+
Vue's runtime prop system uses JavaScript constructor functions, which can't express complex TypeScript types:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// What runtime props support:
|
|
26
|
+
props: {
|
|
27
|
+
name: String, // OK: string
|
|
28
|
+
count: Number, // OK: number
|
|
29
|
+
enabled: Boolean, // OK: boolean
|
|
30
|
+
items: Array, // Problem: any[]
|
|
31
|
+
config: Object, // Problem: Record<string, any>
|
|
32
|
+
handler: Function // Problem: (...args: any[]) => any
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Using PropType for Complex Types
|
|
37
|
+
|
|
38
|
+
**Import and use PropType:**
|
|
39
|
+
```typescript
|
|
40
|
+
import { defineComponent, PropType } from 'vue'
|
|
41
|
+
// or
|
|
42
|
+
import type { PropType } from 'vue'
|
|
43
|
+
|
|
44
|
+
interface User {
|
|
45
|
+
id: number
|
|
46
|
+
name: string
|
|
47
|
+
email: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface Config {
|
|
51
|
+
theme: 'light' | 'dark'
|
|
52
|
+
maxItems: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default defineComponent({
|
|
56
|
+
props: {
|
|
57
|
+
// Object with interface
|
|
58
|
+
user: {
|
|
59
|
+
type: Object as PropType<User>,
|
|
60
|
+
required: true
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// Array of typed items
|
|
64
|
+
users: {
|
|
65
|
+
type: Array as PropType<User[]>,
|
|
66
|
+
default: () => []
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Object with union type
|
|
70
|
+
config: {
|
|
71
|
+
type: Object as PropType<Config>,
|
|
72
|
+
default: () => ({ theme: 'light', maxItems: 10 })
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// Typed function
|
|
76
|
+
onSubmit: {
|
|
77
|
+
type: Function as PropType<(data: User) => Promise<void>>,
|
|
78
|
+
required: true
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// Union of primitives
|
|
82
|
+
id: {
|
|
83
|
+
type: [String, Number] as PropType<string | number>,
|
|
84
|
+
required: true
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// Literal union type
|
|
88
|
+
status: {
|
|
89
|
+
type: String as PropType<'pending' | 'active' | 'completed'>,
|
|
90
|
+
default: 'pending'
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
methods: {
|
|
95
|
+
async handleSubmit() {
|
|
96
|
+
// Full type inference!
|
|
97
|
+
await this.onSubmit(this.user) // onSubmit is properly typed
|
|
98
|
+
console.log(this.user.email) // user.email is string
|
|
99
|
+
console.log(this.config.theme) // theme is 'light' | 'dark'
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Important: Runtime vs Compile-Time
|
|
106
|
+
|
|
107
|
+
PropType only affects TypeScript compilation. At runtime, Vue still only validates using the constructor:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
props: {
|
|
111
|
+
user: {
|
|
112
|
+
type: Object as PropType<User>,
|
|
113
|
+
required: true
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Runtime: Vue only checks typeof value === 'object'
|
|
118
|
+
// It does NOT validate { id, name, email } structure
|
|
119
|
+
|
|
120
|
+
// To add runtime validation, use validator:
|
|
121
|
+
props: {
|
|
122
|
+
user: {
|
|
123
|
+
type: Object as PropType<User>,
|
|
124
|
+
required: true,
|
|
125
|
+
validator: (user: User) => {
|
|
126
|
+
return typeof user.id === 'number' &&
|
|
127
|
+
typeof user.name === 'string' &&
|
|
128
|
+
typeof user.email === 'string'
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Common PropType Patterns
|
|
135
|
+
|
|
136
|
+
### Nullable Props
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
props: {
|
|
140
|
+
// Optional object that can be null
|
|
141
|
+
selectedItem: {
|
|
142
|
+
type: Object as PropType<Item | null>,
|
|
143
|
+
default: null
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Enum-like Props
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
type ButtonVariant = 'primary' | 'secondary' | 'danger'
|
|
152
|
+
|
|
153
|
+
props: {
|
|
154
|
+
variant: {
|
|
155
|
+
type: String as PropType<ButtonVariant>,
|
|
156
|
+
default: 'primary',
|
|
157
|
+
validator: (v: ButtonVariant) =>
|
|
158
|
+
['primary', 'secondary', 'danger'].includes(v)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Generic-like Props with Multiple Types
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
props: {
|
|
167
|
+
// Accept string, number, or object with id
|
|
168
|
+
value: {
|
|
169
|
+
type: [String, Number, Object] as PropType<string | number | { id: string }>,
|
|
170
|
+
required: true
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Event Handler Props
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
interface ClickEventData {
|
|
179
|
+
item: Item
|
|
180
|
+
index: number
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
props: {
|
|
184
|
+
onClick: {
|
|
185
|
+
type: Function as PropType<(data: ClickEventData) => void>,
|
|
186
|
+
required: false
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Why Not Just Use `as`?
|
|
192
|
+
|
|
193
|
+
You might think to skip `PropType`:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// WRONG - doesn't work as expected
|
|
197
|
+
props: {
|
|
198
|
+
user: Object as User // TypeScript error or incorrect inference
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// CORRECT - use PropType
|
|
202
|
+
props: {
|
|
203
|
+
user: Object as PropType<User>
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`PropType<T>` is specifically designed to work with Vue's prop type system.
|
|
208
|
+
|
|
209
|
+
## Reference
|
|
210
|
+
|
|
211
|
+
- [Vue.js TypeScript with Options API - Typing Component Props](https://vuejs.org/guide/typescript/options-api.html#typing-component-props)
|
|
212
|
+
- [Vue.js Props Documentation](https://vuejs.org/guide/components/props.html)
|
package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Provide/Inject Has Limited Type Inference in Options API
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Injected properties in Options API are not automatically typed, requiring manual type assertions or type augmentation
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, typescript, options-api, provide-inject, type-safety]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Provide/Inject Has Limited Type Inference in Options API
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - When using `provide/inject` with the Options API and TypeScript, injected properties won't be automatically typed. TypeScript will show errors that the property doesn't exist on the component, even though it works at runtime.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Be aware that Options API inject has limited type support
|
|
16
|
+
- [ ] Use type augmentation to add types to injected values
|
|
17
|
+
- [ ] Consider using typed computed wrappers for injected values
|
|
18
|
+
|
|
19
|
+
## The Problem
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// Provider component (parent)
|
|
23
|
+
import { defineComponent } from 'vue'
|
|
24
|
+
|
|
25
|
+
export default defineComponent({
|
|
26
|
+
provide() {
|
|
27
|
+
return {
|
|
28
|
+
theme: 'dark',
|
|
29
|
+
user: { id: 1, name: 'John' }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Consumer component (child) - Options API
|
|
37
|
+
import { defineComponent } from 'vue'
|
|
38
|
+
|
|
39
|
+
export default defineComponent({
|
|
40
|
+
inject: ['theme', 'user'],
|
|
41
|
+
|
|
42
|
+
mounted() {
|
|
43
|
+
// TypeScript Error: Property 'theme' does not exist on type...
|
|
44
|
+
console.log(this.theme)
|
|
45
|
+
|
|
46
|
+
// TypeScript Error: Property 'user' does not exist on type...
|
|
47
|
+
console.log(this.user.name)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Solution 1: Type Augmentation
|
|
53
|
+
|
|
54
|
+
Augment the component type to include injected properties:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// types/injections.d.ts
|
|
58
|
+
import 'vue'
|
|
59
|
+
|
|
60
|
+
declare module 'vue' {
|
|
61
|
+
interface ComponentCustomProperties {
|
|
62
|
+
theme: 'light' | 'dark'
|
|
63
|
+
user: { id: number; name: string }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export {}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// Consumer component - now typed
|
|
72
|
+
import { defineComponent } from 'vue'
|
|
73
|
+
|
|
74
|
+
export default defineComponent({
|
|
75
|
+
inject: ['theme', 'user'],
|
|
76
|
+
|
|
77
|
+
mounted() {
|
|
78
|
+
// Now works - typed from ComponentCustomProperties
|
|
79
|
+
console.log(this.theme) // 'light' | 'dark'
|
|
80
|
+
console.log(this.user.name) // string
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Note**: This adds types globally to ALL components, not just those that inject these values.
|
|
86
|
+
|
|
87
|
+
## Solution 2: Typed Computed Wrappers
|
|
88
|
+
|
|
89
|
+
Use the object syntax with computed property wrappers for type safety:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { defineComponent } from 'vue'
|
|
93
|
+
|
|
94
|
+
interface User {
|
|
95
|
+
id: number
|
|
96
|
+
name: string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default defineComponent({
|
|
100
|
+
inject: {
|
|
101
|
+
theme: {
|
|
102
|
+
from: 'theme',
|
|
103
|
+
default: 'light'
|
|
104
|
+
},
|
|
105
|
+
user: {
|
|
106
|
+
from: 'user',
|
|
107
|
+
default: () => ({ id: 0, name: 'Guest' })
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
computed: {
|
|
112
|
+
// Type via computed wrapper
|
|
113
|
+
typedTheme(): 'light' | 'dark' {
|
|
114
|
+
return this.theme as 'light' | 'dark'
|
|
115
|
+
},
|
|
116
|
+
typedUser(): User {
|
|
117
|
+
return this.user as User
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
mounted() {
|
|
122
|
+
console.log(this.typedTheme)
|
|
123
|
+
console.log(this.typedUser.name)
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Why This Happens
|
|
129
|
+
|
|
130
|
+
The Options API `inject` array syntax `inject: ['theme']` doesn't provide type information to TypeScript. Vue knows about the injection at runtime, but TypeScript's static analysis can't trace the provide/inject relationship across components.
|
|
131
|
+
|
|
132
|
+
## Reference
|
|
133
|
+
|
|
134
|
+
- [Vue.js Provide/Inject](https://vuejs.org/guide/components/provide-inject.html)
|
|
135
|
+
- [GitHub Issue: Add type inference to Options API provide/inject](https://github.com/vuejs/core/issues/3031)
|