chore: restore files unintentionally deleted in 6c61a4e

This commit is contained in:
yeuimu
2026-08-26 17:54:35 +08:00
parent 6c61a4e871
commit 005ab5b585
486 changed files with 114058 additions and 0 deletions
@@ -0,0 +1,161 @@
---
title: defineProps Cannot Access Variables from script setup
impact: MEDIUM
impactDescription: Variables declared in script setup are not accessible inside defineProps arguments
type: gotcha
tags: [vue3, props, script-setup, defineProps, compiler]
---
# defineProps Cannot Access Variables from script setup
**Impact: MEDIUM** - Code inside the `defineProps()` argument cannot access other variables declared in `<script setup>`. The entire expression is moved to an outer function scope when compiled, making local variables inaccessible.
This commonly surprises developers trying to use imported constants or computed validation logic.
## Task Checklist
- [ ] Define validation constants outside `<script setup>` or in a separate file
- [ ] Import constants before using them in defineProps
- [ ] Use external type definitions for TypeScript props
- [ ] For dynamic validation, use watchers instead of prop validators
**Incorrect:**
```vue
<script setup>
import { ref } from 'vue'
// These are in <script setup> scope
const VALID_SIZES = ['sm', 'md', 'lg']
const maxLength = ref(100)
defineProps({
size: {
type: String,
// WRONG: VALID_SIZES is not accessible here
validator: (v) => VALID_SIZES.includes(v) // ReferenceError!
},
name: {
type: String,
// WRONG: Cannot access refs
validator: (v) => v.length <= maxLength.value // ReferenceError!
}
})
</script>
```
**Correct:**
```vue
<script>
// Define constants in regular <script> block (module scope)
export const VALID_SIZES = ['sm', 'md', 'lg']
export const MAX_LENGTH = 100
</script>
<script setup>
// Now accessible in defineProps
defineProps({
size: {
type: String,
validator: (v) => VALID_SIZES.includes(v) // Works!
},
name: {
type: String,
validator: (v) => v.length <= MAX_LENGTH // Works!
}
})
</script>
```
## Pattern: Import from External File
```javascript
// validation.js
export const VALID_SIZES = ['sm', 'md', 'lg']
export const VALID_COLORS = ['red', 'blue', 'green']
export const sizeValidator = (v) => VALID_SIZES.includes(v)
```
```vue
<script setup>
import { VALID_SIZES, VALID_COLORS, sizeValidator } from './validation'
// Imported values ARE accessible
defineProps({
size: {
type: String,
validator: sizeValidator
},
color: {
type: String,
validator: (v) => VALID_COLORS.includes(v)
}
})
</script>
```
## Pattern: Dual Script Blocks
```vue
<script>
// Regular script for module-level declarations
const options = {
themes: ['light', 'dark', 'system'],
defaults: {
theme: 'light',
size: 'md'
}
}
</script>
<script setup>
// options is accessible here
const props = defineProps({
theme: {
type: String,
default: options.defaults.theme,
validator: (v) => options.themes.includes(v)
}
})
</script>
```
## TypeScript: External Type Definitions
```typescript
// types.ts
export interface UserProps {
name: string
email: string
age?: number
}
```
```vue
<script setup lang="ts">
import type { UserProps } from './types'
// Type imports work fine
const props = defineProps<UserProps>()
</script>
```
## Why This Happens
Vue's compiler transforms `<script setup>` code. The `defineProps()` call is extracted and moved to component options at compile time, before the setup function runs:
```javascript
// Your code:
const MY_CONST = 'value'
defineProps({ prop: { default: MY_CONST } })
// Compiled (simplified):
export default {
props: { prop: { default: MY_CONST } }, // MY_CONST doesn't exist here!
setup() {
const MY_CONST = 'value' // Defined too late
}
}
```
## Reference
- [Vue.js Script Setup - defineProps](https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits)