Skip to main content

typescript-patterns

TypeScript types: generics, discriminated unions, Zod, satisfies, branded types. Triggers: TypeScript, TS, generics, Zod, satisfies, strict mode.

Informations de source

Dépôt
softspark/ai-toolkit
Dernière activité de la source
6 mai 2026 à 09:48
Langue détectée de SKILL.md
anglais
Étoiles
179
Forks
21

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
typescript-patterns
description
TypeScript types: generics, discriminated unions, Zod, satisfies, branded types. Triggers: TypeScript, TS, generics, Zod, satisfies, strict mode.
effort
medium
user-invocable
false
allowed-tools
Read
# TypeScript/JavaScript Patterns ## TypeScript Configuration ### Strict tsconfig.json ```json { "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "exactOptionalPropertyTypes": true, "moduleResolution": "bundler", "module": "ESNext", "target": "ES2022", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "isolatedModules": true, "declaration": true, "declarationMap": true, "sourceMap": true, "outDir": "./dist", "rootDir": "./src" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } ``` ## ESLint + Prettier ```json // .eslintrc.json (flat config recommended for new projects) { "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended-type-checked", "prettier" ], "parser": "@typescript-eslint/parser", "parserOptions": { "project": "./tsconfig.json" }, "rules": { "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], "@typescript-eslint/no-floating-promises": "error", "@typescript-eslint/no-misused-promises": "error" } } ``` ## React Patterns ### Functional Component ```tsx interface UserCardProps { user: User; onSelect?: (id: string) => void; } export function UserCard({ user, onSelect }: UserCardProps) { const handleClick = useCallback(() => { onSelect?.(user.id); }, [user.id, onSelect]); return ( <div onClick={handleClick} role="button" tabIndex={0}> <h3>{user.name}</h3> <p>{user.email}</p> </div> ); } ``` ### Custom Hook ```tsx function useAsync<T>(fn: () => Promise<T>, deps: unknown[]) { const [state, setState] = useState<{ data: T | null; error: Error | null; loading: boolean; }>({ data: null, error: null, loading: true }); useEffect(() => { let cancelled = false; setState(prev => ({ ...prev, loading: true })); fn() .then(data => { if (!cancelled) setState({ data, error: null, loading: false }); }) .catch(error => { if (!cancelled) setState({ data: null, error, loading: false }); }); return () => { cancelled = true; }; }, deps); return state; } ``` ### Context Pattern ```tsx interface AuthContextType { user: User | null; login: (credentials: Credentials) => Promise<void>; logout: () => void; } const AuthContext = createContext<AuthContextType | null>(null); export function useAuth() { const context = useContext(AuthContext); if (!context) throw new Error("useAuth must be within AuthProvider"); return context; } ``` ## Next.js App Router ### Server Component (default) ```tsx // app/users/page.tsx export default async function UsersPage() { const users = await db.user.findMany(); return <UserList users={users} />; } ``` ### Server Action ```tsx "use server"; import { revalidatePath } from "next/cache"; export async function createUser(formData: FormData) { const name = formData.get("name") as string; await db.user.create({ data: { name } }); revalidatePath("/users"); } ``` ## Node.js/Express Patterns ### Type-safe Route Handler ```typescript import { Router, Request, Response } from "express"; import { z } from "zod"; const CreateUserSchema = z.object({ name: z.string().min(1).max(100), email: z.string().email(), }); router.post("/users", async (req: Request, res: Response) => { const result = CreateUserSchema.safeParse(req.body); if (!result.success) { return res.status(400).json({ errors: result.error.flatten() }); } const user = await userService.create(result.data); res.status(201).json(user); }); ``` ## State Management ### Zustand Store ```typescript import { create } from "zustand"; interface CartStore { items: CartItem[]; addItem: (item: CartItem) => void; removeItem: (id: string) => void; total: () => number; } export const useCartStore = create<CartStore>((set, get) => ({ items: [], addItem: (item) => set((state) => ({ items: [...state.items, item] })), removeItem: (id) => set((state) => ({ items: state.items.filter(i => i.id !== id) })), total: () => get().items.reduce((sum, item) => sum + item.price, 0), })); ``` ## Type-safe API (tRPC / Zod) ### Zod Schema Validation ```typescript import { z } from "zod"; export const UserSchema = z.object({ id: z.string().uuid(), name: z.string().min(1).max(100), email: z.string().email(), role: z.enum(["admin", "user", "guest"]), createdAt: z.coerce.date(), }); export type User = z.infer<typeof UserSchema>; ``` ## Error Handling ```typescript class AppError extends Error { constructor( message: string, public statusCode: number = 500, public code: string = "INTERNAL_ERROR" ) { super(message); this.name = "AppError"; } } // Result pattern (no exceptions) type Result<T, E = Error> = | { success: true; data: T } | { success: false; error: E }; function parseUser(raw: unknown): Result<User> { const result = UserSchema.safeParse(raw); if (result.success) return { success: true, data: result.data }; return { success: false, error: new Error(result.error.message) }; } ``` ## Testing with Vitest ```typescript import { describe, it, expect, vi } from "vitest"; describe("UserService", () => { it("creates user with valid data", async () => { const mockRepo = { create: vi.fn().mockResolvedValue({ id: "1", name: "Test" }) }; const service = new UserService(mockRepo); const user = await service.create({ name: "Test", email: "t@t.com" }); expect(user.id).toBe("1"); expect(mockRepo.create).toHaveBeenCalledOnce(); }); }); ``` ## Anti-Patterns - `any` type usage (use `unknown` and narrow) - Non-null assertions `!` without checks - `as` type casting instead of type guards - Mutable state in React (use immutable updates) - Missing error boundaries in React - Barrel exports that break tree-shaking
Voir sur GitHub