UNPKG

oneie

Version:

Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.

322 lines (243 loc) 6.8 kB
--- title: Typescript Patterns dimension: knowledge category: typescript-patterns.md tags: ai related_dimensions: groups, things scope: global created: 2025-11-03 updated: 2025-11-03 version: 1.0.0 ai_context: | This document is part of the knowledge dimension in the typescript-patterns.md category. Location: one/knowledge/typescript-patterns.md Purpose: Documents typescript patterns & best practices Related dimensions: groups, things For AI agents: Read this to understand typescript patterns. --- # TypeScript Patterns & Best Practices ## Common Type Issues & Fixes ### 1. Lucide React Icon Types **Problem:** Icon type definitions using function signatures fail with React 19 + Lucide React. **Error:** ``` error ts(2322): Type 'ForwardRefExoticComponent<Omit<LucideProps, "ref"> & RefAttributes<SVGSVGElement>>' is not assignable to type '(props: SVGProps<SVGSVGElement>) => Element'. Type 'ReactNode' is not assignable to type 'Element'. ``` **Bad Pattern:** ```typescript import { Sparkles, Code2 } from 'lucide-react'; type Tool = { id: string; label: string; // WRONG: Function signature icon: (props: React.SVGProps<SVGSVGElement>) => React.JSX.Element; }; const TOOLS: Tool[] = [ { id: "claude", label: "Claude Code", icon: Sparkles, // Type error! } ]; ``` **Good Pattern:** ```typescript import { Sparkles, Code2 } from 'lucide-react'; type Tool = { id: string; label: string; // CORRECT: Component type icon: React.ComponentType<React.SVGProps<SVGSVGElement>>; }; const TOOLS: Tool[] = [ { id: "claude", label: "Claude Code", icon: Sparkles, // Works! } ]; ``` **Why:** Lucide icons are `ForwardRefExoticComponent`, not regular functions. Use `ComponentType` for component references. --- ### 2. React 19 Component Props **Problem:** Props types not compatible with React 19's stricter typing. **Bad Pattern:** ```typescript // ❌ Old React patterns interface ButtonProps { children: React.ReactNode; onClick: () => void; } const Button = ({ children, onClick }: ButtonProps) => { return <button onClick={onClick}>{children}</button>; }; ``` **Good Pattern:** ```typescript // ✅ React 19 recommended import { type ReactNode } from 'react'; interface ButtonProps { children: ReactNode; onClick: () => void; } export function Button({ children, onClick }: ButtonProps) { return <button onClick={onClick}>{children}</button>; } ``` **Why:** React 19 prefers named exports and direct ReactNode imports for cleaner types. --- ### 3. SVG Component Types **Bad Pattern:** ```typescript // Inconsistent with Lucide type CustomIcon = (props: React.SVGProps<SVGSVGElement>) => JSX.Element; ``` **Good Pattern:** ```typescript // Matches Lucide pattern type IconProps = React.SVGProps<SVGSVGElement>; type CustomIcon = React.ComponentType<IconProps>; // Usage const MyIcon: CustomIcon = (props) => ( <svg {...props}> <path d="..." /> </svg> ); ``` **Why:** Consistency with library patterns makes code more maintainable. --- ### 4. Astro + React Integration **Problem:** Type mismatches between Astro and React components. **Bad Pattern:** ```astro --- // No type safety import Button from '@/components/Button'; const data = await fetch('...').then(r => r.json()); --- <Button onClick={() => console.log(data)} /> ``` **Good Pattern:** ```astro --- // Type-safe props import Button from '@/components/ui/button'; import type { ApiResponse } from '@/types'; const data: ApiResponse = await fetch('...') .then(r => r.json()); --- <Button client:load onClick={() => console.log(data)}> Click me </Button> ``` **Why:** Explicit types catch errors at build time, not runtime. --- ### 5. Generic Component Props **Bad Pattern:** ```typescript // Any destroys type safety interface FormProps { onSubmit: (data: any) => void; } ``` **Good Pattern:** ```typescript // Generic for type safety interface FormProps<T> { onSubmit: (data: T) => void; initialData?: T; } function Form<T>({ onSubmit, initialData }: FormProps<T>) { // Type-safe implementation } // Usage interface LoginData { email: string; password: string; } <Form<LoginData> onSubmit={(data) => { // data is typed as LoginData! console.log(data.email); }} /> ``` **Why:** Generics preserve type information through component boundaries. --- ## Diagnostic Commands ### Find Type Errors ```bash # Full type check (Astro + TypeScript) bunx astro check # Filter errors only bunx astro check 2>&1 | grep "error" # Filter by file bunx astro check 2>&1 | grep "SendToTools" # Count errors bunx astro check 2>&1 | grep -c "error" ``` ### Regenerate Types ```bash # Regenerate Astro content types bunx astro sync # Full rebuild bunx astro build # Type check without building bunx astro check --minimumSeverity error ``` --- ## React 19 + Astro Compatibility ### Key Changes in React 19 1. **Server Components** - Use `'use client'` directive when needed 2. **Stricter Types** - More precise type cycle 3. **New Hooks** - `useFormStatus`, `useFormState`, `useOptimistic` 4. **Async Components** - Server components can be async ### Astro Integration Best Practices ```typescript // GOOD: Client directive for interactivity <Button client:load onClick={handler}>Click</Button> // BAD: Missing client directive <Button onClick={handler}>Click</Button> // GOOD: Server-side data fetching --- const data = await fetch('https://api.example.com/data') .then(r => r.json()); --- <DataDisplay data={data} /> // GOOD: Client component with hydration <InteractiveChart client:load data={data} /> ``` --- ## Common Fixes Checklist When encountering type errors: - [ ] Check if using `React.ComponentType` for component references - [ ] Verify `client:load` on interactive React components - [ ] Run `bunx astro sync` to regenerate content types - [ ] Check import statements (named vs default exports) - [ ] Verify React 19 compatibility - [ ] Look for `any` types - replace with proper types - [ ] Check prop spreading (`{...props}`) types - [ ] Verify generic constraints are met --- ## Testing Type Safety ```typescript // Create a type test file // types.test.ts import { expectType } from 'tsd'; import type { Tool } from './Tool'; // Test icon type expectType<React.ComponentType<React.SVGProps<SVGSVGElement>>>( tool.icon ); ``` --- ## Documentation References - **React 19 Types:** https://react.dev/blog/2024/04/25/react-19-upgrade-guide - **Astro TypeScript:** https://docs.astro.build/en/guides/typescript/ - **Lucide React:** https://lucide.dev/guide/packages/lucide-react --- **Last Updated:** v3.0.3 (Icon type fixes) **Category:** Knowledge / TypeScript **Ontology Dimension:** Knowledge (technical patterns)