From 37559e1bad5a54de18a95b4e239122ef52c128e8 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Sat, 16 Aug 2025 14:50:14 +0000 Subject: [PATCH] docs(typescript): add comprehensive type safety guidelines with Vue exceptions 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 codebase --- .../rules/development/type_safety_guide.mdc | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .cursor/rules/development/type_safety_guide.mdc diff --git a/.cursor/rules/development/type_safety_guide.mdc b/.cursor/rules/development/type_safety_guide.mdc new file mode 100644 index 00000000..507e3f23 --- /dev/null +++ b/.cursor/rules/development/type_safety_guide.mdc @@ -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/