diff --git a/.cursor/rules/typescript_rules.mdc b/.cursor/rules/typescript_rules.mdc new file mode 100644 index 0000000..2eafacb --- /dev/null +++ b/.cursor/rules/typescript_rules.mdc @@ -0,0 +1,107 @@ +--- +description: Guidelines for TypeScript usage, including type safety rules and Convex query typing +globs: **/*.ts,**/*.tsx,**/*.svelte +--- + +# TypeScript Guidelines + +## Type Safety Rules + +### Avoid `any` Type +- **NEVER** use the `any` type in production code +- The only exception is in test files (files matching `*.test.ts`, `*.test.tsx`, `*.spec.ts`, `*.spec.tsx`) +- Instead of `any`, use: + - Proper type definitions + - `unknown` for truly unknown types (with type guards) + - Generic types (``) when appropriate + - Union types when multiple types are possible + - `Record` for objects with unknown structure + +### Examples + +**❌ Bad:** +```typescript +function processData(data: any) { + return data.value; +} +``` + +**✅ Good:** +```typescript +function processData(data: { value: string }) { + return data.value; +} + +// Or with generics +function processData(data: T) { + return data.value; +} + +// Or with unknown and type guards +function processData(data: unknown) { + if (typeof data === 'object' && data !== null && 'value' in data) { + return (data as { value: string }).value; + } + throw new Error('Invalid data'); +} +``` + +**✅ Exception (tests only):** +```typescript +// test.ts or *.spec.ts +it('should handle any input', () => { + const input: any = getMockData(); + expect(process(input)).toBeDefined(); +}); +``` + +## Convex Query Typing + +### Frontend Query Usage +- **DO NOT** create manual type definitions for Convex query results in the frontend +- Convex queries already return properly typed results based on their `returns` validator +- The TypeScript types are automatically inferred from the query's return validator +- Simply use the query result directly - TypeScript will infer the correct type + +### Examples + +**❌ Bad:** +```typescript +// Don't manually type the result +type UserListResult = Array<{ + _id: Id<"users">; + name: string; +}>; + +const users: UserListResult = useQuery(api.users.list); +``` + +**✅ Good:** +```typescript +// Let TypeScript infer the type from the query +const users = useQuery(api.users.list); +// TypeScript automatically knows the type based on the query's returns validator + +// You can still use it with type inference +if (users !== undefined) { + users.forEach(user => { + // TypeScript knows user._id is Id<"users"> and user.name is string + console.log(user.name); + }); +} +``` + +**✅ Good (with explicit type if needed for clarity):** +```typescript +// Only if you need to export or explicitly annotate for documentation +import type { FunctionReturnType } from "convex/server"; +import type { api } from "./convex/_generated/api"; + +type UserListResult = FunctionReturnType; +const users = useQuery(api.users.list); +``` + +### Best Practices +- Trust Convex's type inference - it's based on your schema and validators +- If you need type annotations, use `FunctionReturnType` from Convex's type utilities +- Only create manual types if you're doing complex transformations that need intermediate types