feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma binaryTargets for openssl 3.0 - nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal cron, http->https redirect - prisma: add origin_goods.delisted migration, sync missing schema (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz - api: CORS wildcard reflection, helmet CORP cross-origin, price backfill in persistProductDetail, categoryIcon ancestor fallback, mediaByColor per-color gallery in public goods detail - admin: /admin base path (vite + router) - import-data.mjs: udt_name casting, serial sequence advance fix
This commit is contained in:
-197
@@ -1,197 +0,0 @@
|
||||
---
|
||||
title: Enable strict Mode for Proper Options API TypeScript Support
|
||||
impact: HIGH
|
||||
impactDescription: Without strict mode, 'this' in Options API components is typed as 'any', losing all type safety
|
||||
type: gotcha
|
||||
tags: [typescript, options-api, tsconfig, this-typing, configuration]
|
||||
---
|
||||
|
||||
# Enable strict Mode for Proper Options API TypeScript Support
|
||||
|
||||
**Impact: HIGH** - Without `strict: true` (or at minimum `noImplicitThis: true`) in your tsconfig.json, the `this` context in Options API components is typed as `any`. This silently disables type checking for all property access on component instances.
|
||||
|
||||
## Task Checklist
|
||||
|
||||
- [ ] Enable `strict: true` in tsconfig.json (recommended)
|
||||
- [ ] Or enable `noImplicitThis: true` at minimum
|
||||
- [ ] Wrap components with `defineComponent()` for proper inference
|
||||
- [ ] Verify type errors appear when accessing non-existent properties
|
||||
|
||||
## The Problem
|
||||
|
||||
TypeScript's default behavior without strict mode allows implicit `any` typing, which defeats the purpose of using TypeScript with Vue's Options API.
|
||||
|
||||
**tsconfig.json without strict mode:**
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020"
|
||||
// No strict mode - this is DANGEROUS
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Component with hidden type errors:**
|
||||
```typescript
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
count: 0,
|
||||
message: 'Hello'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
increment() {
|
||||
// Without strict mode, these errors are SILENT:
|
||||
this.cont++ // Typo: should be 'count'
|
||||
this.nonExistent // Property doesn't exist
|
||||
this.message.toFixed() // Wrong method for string
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
All of the above errors compile successfully without strict mode because `this` is implicitly `any`.
|
||||
|
||||
## Correct Configuration
|
||||
|
||||
**Recommended tsconfig.json:**
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"isolatedModules": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Minimum for Options API type safety:**
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitThis": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What strict Mode Enables
|
||||
|
||||
The `strict` flag is a shorthand for enabling multiple type-checking options:
|
||||
|
||||
| Option | Effect |
|
||||
|--------|--------|
|
||||
| `noImplicitThis` | Errors on `this` with implicit `any` type |
|
||||
| `noImplicitAny` | Errors on expressions with implicit `any` type |
|
||||
| `strictNullChecks` | null and undefined are distinct types |
|
||||
| `strictFunctionTypes` | Stricter function parameter checking |
|
||||
| `strictPropertyInitialization` | Class properties must be initialized |
|
||||
| `strictBindCallApply` | Stricter bind, call, apply typing |
|
||||
| `alwaysStrict` | Emits "use strict" in output |
|
||||
|
||||
## Correct Component with Proper Typing
|
||||
|
||||
```typescript
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
count: 0,
|
||||
message: 'Hello'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
doubleCount(): number {
|
||||
return this.count * 2 // 'this.count' is typed as number
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
increment() {
|
||||
this.count++ // Type-safe: count is number
|
||||
// this.cont++ // ERROR: Property 'cont' does not exist
|
||||
},
|
||||
greet(name: string) {
|
||||
return `${this.message}, ${name}!` // Type-safe
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Common Errors After Enabling Strict Mode
|
||||
|
||||
### Error: Property 'xxx' does not exist
|
||||
|
||||
```typescript
|
||||
// Before: worked silently
|
||||
this.unknownProp
|
||||
|
||||
// After: TypeScript error
|
||||
// Property 'unknownProp' does not exist on type 'ComponentPublicInstance<...>'
|
||||
```
|
||||
|
||||
Fix by adding the property to `data()` or declaring it properly.
|
||||
|
||||
### Error: Object is possibly 'undefined'
|
||||
|
||||
```typescript
|
||||
methods: {
|
||||
getFirst() {
|
||||
const items = this.items
|
||||
// Error: Object is possibly 'undefined'
|
||||
return items[0].name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Fix with proper null checks:
|
||||
```typescript
|
||||
methods: {
|
||||
getFirst() {
|
||||
return this.items?.[0]?.name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Important: defineComponent is Required
|
||||
|
||||
Even with strict mode, you must use `defineComponent()` to enable proper type inference:
|
||||
|
||||
```typescript
|
||||
// BAD - No type inference for 'this'
|
||||
export default {
|
||||
data() {
|
||||
return { count: 0 }
|
||||
},
|
||||
methods: {
|
||||
increment() {
|
||||
this.count++ // 'this' is any even with strict mode!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD - Full type inference
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return { count: 0 }
|
||||
},
|
||||
methods: {
|
||||
increment() {
|
||||
this.count++ // 'this.count' is properly typed as number
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
- [Vue.js TypeScript Overview - tsconfig.json](https://vuejs.org/guide/typescript/overview.html#configuring-tsconfig-json)
|
||||
- [Vue.js TypeScript with Options API](https://vuejs.org/guide/typescript/options-api.html)
|
||||
- [TypeScript strict Mode](https://www.typescriptlang.org/tsconfig#strict)
|
||||
Reference in New Issue
Block a user