Browse Source
Create TypeScript type safety guidelines enforcing strict typing across TimeSafari codebase. Includes special cases for Vue objects, dynamic component access, and framework integration where any types are necessary. - Enforce no-any rule with documented exceptions - Add Vue-specific edge cases (component instances, template refs, events) - Include third-party library and platform API handling - Provide migration checklists and code review guidelines - Document error handling patterns and anti-patterns - Add examples from existing codebasepull/152/head^2
1 changed files with 108 additions and 0 deletions
@ -0,0 +1,108 @@ |
|||
--- |
|||
globs: **/src/**/*,**/scripts/**/*,**/electron/**/* |
|||
alwaysApply: false |
|||
--- |
|||
```json |
|||
{ |
|||
"coaching_level": "light", |
|||
"socratic_max_questions": 7, |
|||
"verbosity": "concise", |
|||
"timebox_minutes": null, |
|||
"format_enforcement": "strict" |
|||
} |
|||
``` |
|||
|
|||
# TypeScript Type Safety Guidelines |
|||
|
|||
**Author**: Matthew Raymer |
|||
**Date**: 2025-08-16 |
|||
**Status**: 🎯 **ACTIVE** |
|||
|
|||
## Overview |
|||
|
|||
Practical rules to keep TypeScript strict and predictable. Minimize exceptions. |
|||
|
|||
## Core Rules |
|||
|
|||
1. **No `any`** |
|||
- Use explicit types. If unknown, use `unknown` and **narrow** via guards. |
|||
|
|||
2. **Error handling uses guards** |
|||
- Reuse guards from `src/interfaces/**` (e.g., `isDatabaseError`, `isApiError`). |
|||
- Catch with `unknown`; never cast to `any`. |
|||
|
|||
3. **Dynamic property access is type‑safe** |
|||
- Use `keyof` + `in` checks: |
|||
|
|||
```ts |
|||
obj[k as keyof typeof obj] |
|||
``` |
|||
|
|||
- Avoid `(obj as any)[k]`. |
|||
|
|||
## Minimal Special Cases (document in PR when used) |
|||
|
|||
- **Vue refs / instances**: Use `ComponentPublicInstance` or specific component |
|||
types for dynamic refs. |
|||
- **3rd‑party libs without types**: Narrow immediately to a **known interface**; |
|||
do not leave `any` hanging. |
|||
|
|||
## Patterns (short) |
|||
|
|||
### Database errors |
|||
|
|||
```ts |
|||
try { await this.$addContact(contact); } |
|||
catch (e: unknown) { |
|||
if (isDatabaseError(e) && e.message.includes("Key already exists")) { |
|||
/* handle duplicate */ |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### API errors |
|||
|
|||
```ts |
|||
try { await apiCall(); } |
|||
catch (e: unknown) { |
|||
if (isApiError(e)) { |
|||
const msg = e.response?.data?.error?.message; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Dynamic keys |
|||
|
|||
```ts |
|||
const keys = Object.keys(newSettings).filter( |
|||
k => k in newSettings && newSettings[k as keyof typeof newSettings] !== undefined |
|||
); |
|||
``` |
|||
|
|||
## Checklists |
|||
|
|||
**Before commit** |
|||
|
|||
- [ ] No `any` (except documented, justified cases) |
|||
- [ ] Errors handled via guards |
|||
- [ ] Dynamic access uses `keyof`/`in` |
|||
- [ ] Imports point to correct interfaces/types |
|||
|
|||
**Code review** |
|||
|
|||
- [ ] Hunt hidden `as any` |
|||
- [ ] Guard‑based error paths verified |
|||
- [ ] Dynamic ops are type‑safe |
|||
- [ ] Prefer existing types over re‑inventing |
|||
|
|||
## Tools |
|||
|
|||
- `npm run lint-fix` — lint & auto‑fix |
|||
- `npm run type-check` — strict type compilation (CI + pre‑release) |
|||
- IDE: enable strict TS, ESLint/TS ESLint, Volar (Vue 3) |
|||
|
|||
## References |
|||
|
|||
- TS Handbook — https://www.typescriptlang.org/docs/ |
|||
- TS‑ESLint — https://typescript-eslint.io/rules/ |
|||
- Vue 3 + TS — https://vuejs.org/guide/typescript/ |
Loading…
Reference in new issue