--- name: typescript description: > TypeScript strict patterns and best practices for scalable applications. Trigger: When writing TypeScript code - types, interfaces or generics. license: Apache-2.0 metadata: author: K-test version: "2.0" --- ## Const Types Pattern (REQUIRED) ```typescript // ✅ ALWAYS: Create const object first, then extract type const STATUS = { ACTIVE: "active", INACTIVE: "inactive", PENDING: "pending", } as const; type Status = (typeof STATUS)[keyof typeof STATUS]; // ❌ NEVER: Direct union types type Status = "active" | "inactive" | "pending"; ``` **Why?** Single source of truth, runtime values, autocomplete, easier refactoring. ## Flat Interfaces (REQUIRED) ```typescript // ✅ ALWAYS: One level depth, nested objects → dedicated interface interface UserAddress { street: string; city: string; } interface User { id: string; name: string; address: UserAddress; // Reference, not inline } interface Admin extends User { permissions: string[]; } // ❌ NEVER: Inline nested objects interface User { address: { street: string; city: string }; // NO! } ``` ## Interface vs Type (REQUIRED) ```typescript // ✅ ALWAYS: Use interface for object shapes and variable typings interface User { id: string; name: string; } interface ApiResponse { data: User[]; total: number; } // ✅ ONLY use type when interface cannot do the job: // - Union/intersection types type ID = string | number; type AdminOrUser = Admin | User; // - Mapped types type ReadonlyUser = { readonly [K in keyof User]: User[K] }; // - Conditional types type IsString = T extends string ? true : false; // - Const object type extraction (see Const Types Pattern) type Status = (typeof STATUS)[keyof typeof STATUS]; // - Tuple types type Pair = [string, number]; // ❌ NEVER: Use type for plain object shapes when interface works type User = { // NO — use interface instead id: string; name: string; }; ``` **Why?** Interfaces are extendable (`extends`), give better error messages, support declaration merging, and signal clearly that the shape describes an object. Reserve `type` for operations that interfaces cannot express. ## Never Use `any` ```typescript // ✅ Use unknown for truly unknown types function parse(input: unknown): User { if (isUser(input)) return input; throw new Error("Invalid input"); } // ✅ Use generics for flexible types function first(arr: T[]): T | undefined { return arr[0]; } // ❌ NEVER function parse(input: any): any { } ``` ## Utility Types ```typescript Pick // Select fields Omit // Exclude fields Partial // All optional Required // All required Readonly // All readonly Record // Object type Extract // Extract from union Exclude // Exclude from union NonNullable // Remove null/undefined ReturnType // Function return type Parameters // Function params tuple ``` ## Type Guards ```typescript function isUser(value: unknown): value is User { return ( typeof value === "object" && value !== null && "id" in value && "name" in value ); } ``` ## Import Types ```typescript import type { User } from "./types"; import { createUser, type Config } from "./utils"; ``` ## Keywords typescript, ts, types, interfaces, generics, strict mode, utility types