--- name: typescript-expert description: "Expert guide for TypeScript 5.8+ advanced type system, strict mode, generics, utility types, branded types, inferred type predicates, isolated declarations, and type-safe architectural patterns / Panduan ahli untuk sistem tipe TypeScript 5.8+, mode strict, generics, utility types, branded types, inferred type predicates, isolated declarations, dan pola arsitektur type-safe." author: "Roedy Rustam" version: "4.4.2" --- # TypeScript Expert (TypeScript 5.8+ Edition) [English](#english) | [Bahasa Indonesia](#bahasa-indonesia) --- ## English ### Orchestration & Integration - **Upstream & Foundation**: `zero-to-prod-orchestrator` (Phase 2 foundation), `brainstorming`, `session-memory-manager`. - **AST & Codebase Intelligence**: `living-codebase-ast-graph` (compiler API & type-checker symbols), `scalability-clean-code` (type-safe clean patterns). - **Backend & Fullstack Runtime**: `js-backend-expert` (Node.js/Bun strict types), `database-orm-expert` (Prisma/Drizzle schema type generation). - **Frontend & Monorepos**: `senior-frontend` (React 19 type safety), `monorepo-architect` (composite projects & isolated declarations), `form-validation-expert` (Zod schema inference). ### Description Expert-level TypeScript development covering the advanced type system, strict mode enforcement, generic programming, utility types, branded types, and type-safe patterns for production applications. Targets **TypeScript 5.8+** features including inferred type predicates, isolated declarations, `NoInfer`, `using` declarations, variadic tuple improvements, and `const` type parameters. ### Trigger Conditions - Writing TypeScript with advanced generic constraints. - Enforcing strict type safety in existing codebases. - Designing type-safe API contracts (REST, tRPC, Zod schemas). - Implementing branded types for domain modeling. - Resolving complex type errors or `any` pollution. - Setting up `tsconfig.json` for strict projects. - Writing TypeScript utility types or type helpers. --- ### TypeScript 5.x — Key Features #### `using` Declarations (Explicit Resource Management, TS 5.2) ```typescript // Automatically calls [Symbol.dispose] on scope exit function processFile(path: string) { using handle = openFile(path); // disposed when function exits handle.write('data'); } // Async version with [Symbol.asyncDispose] async function processDatabase() { await using conn = await getConnection(); await conn.query('SELECT 1'); } // conn.close() called automatically ``` #### `NoInfer` Utility Type (TS 5.4) ```typescript // Prevents unintended type widening in generic inference function createState(initial: T, fallback: NoInfer): T { return initial ?? fallback; } // TS now errors if fallback type doesn't match initial createState('hello', 42); // Error: Argument of type 'number' is not assignable to type 'string' ``` #### `const` Type Parameters (TS 5.0) ```typescript // Infer literal types from generic arguments function identity(value: T): T { return value; } const a = identity(['a', 'b', 'c']); // type: readonly ["a", "b", "c"] const b = identity({ x: 10 }); // type: { readonly x: 10 } ``` --- ### TypeScript 5.5 - 5.8 — New Features #### Inferred Type Predicates (TS 5.5) ```typescript // TypeScript now infers type predicates from return statements automatically const nums = [1, null, 2, undefined, 3].filter((x) => x !== null); // nums is now inferred as number[] — no manual type assertion needed! // Before TS 5.5 you needed: const nums = [1, null, 2].filter((x): x is number => x !== null); // Works with any refinement pattern: function isString(x: unknown) { return typeof x === 'string'; // TS 5.5 infers: (x: unknown) => x is string } ``` #### Isolated Declarations (TS 5.5) ```typescript // New tsconfig option: "isolatedDeclarations": true // Forces explicit return types on all exported functions — enables // parallel .d.ts generation (massively speeds up monorepo builds) export function add(a: number, b: number): number { // explicit return type required return a + b; } ``` #### Iterator Helper Methods (TS 5.6 — ES2025) ```typescript // Native iterator methods now fully typed const result = [1, 2, 3, 4, 5] .values() // IteratorObject .filter(x => x % 2 === 0) // 2, 4 .map(x => x * 10) // 20, 40 .toArray(); // [20, 40] ``` --- ### Strict Mode Configuration ```json // tsconfig.json — recommended strict config for Next.js / monorepo projects { "compilerOptions": { "target": "ES2022", "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "Preserve", "moduleResolution": "Bundler", "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "isolatedModules": true, "isolatedDeclarations": true, "verbatimModuleSyntax": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true } } ``` > **Note**: Use `"moduleResolution": "Bundler"` with `"module": "Preserve"` for Vite, Next.js, and other bundler-based projects. Use `"NodeNext"` for Node.js/Bun/Deno runtimes. --- ### Advanced Type Patterns #### Branded Types for Domain Modeling ```typescript // Prevent mixing semantically different primitives type Brand = T & { readonly __brand: B }; type UserId = Brand; type PostId = Brand; type Email = Brand; // Constructor functions with validation function createUserId(id: string): UserId { if (!id.startsWith('user_')) throw new Error('Invalid user ID format'); return id as UserId; } function getUser(id: UserId): Promise { /* ... */ } const postId = 'post_abc' as PostId; getUser(postId); // Compile error: PostId is not assignable to UserId ``` #### Discriminated Unions for State Machines ```typescript type ApiState = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: T } | { status: 'error'; error: Error }; function render(state: ApiState) { switch (state.status) { case 'idle': return 'Idle'; case 'loading': return 'Loading...'; case 'success': return `Data: ${JSON.stringify(state.data)}`; case 'error': return `Error: ${state.error.message}`; // TypeScript enforces exhaustive matching } } ``` #### Template Literal Types ```typescript type EventName = 'click' | 'focus' | 'blur'; type HandlerName = `on${Capitalize}`; // Result: 'onClick' | 'onFocus' | 'onBlur' type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K]; }; type Paths = { [K in keyof T & string]: T[K] extends object ? Paths : `${Prefix}${K}`; }[keyof T & string]; // Paths<{ user: { name: string; age: number } }> = "user.name" | "user.age" ``` #### Conditional Types and `infer` ```typescript type UnwrapPromise = T extends Promise ? U : T; type ArrayElement = T extends (infer U)[] ? U : never; type ReturnType = T extends (...args: any[]) => infer R ? R : never; // Extract function parameter types type Parameters any> = T extends (...args: infer P) => any ? P : never; ``` --- ### Type-Safe Patterns #### Zod Schema + TypeScript Integration ```typescript import { z } from 'zod'; const UserSchema = z.object({ id: z.string().cuid(), email: z.string().email(), role: z.enum(['USER', 'ADMIN']), createdAt: z.coerce.date(), }); type User = z.infer; // Derive type from schema // Type-safe parsing with error handling function parseUser(data: unknown): User { return UserSchema.parse(data); // throws ZodError on failure } const safeResult = UserSchema.safeParse(data); if (safeResult.success) { console.log(safeResult.data.email); // fully typed } ``` #### Type-Safe Environment Variables ```typescript // env.ts — validate env at startup import { z } from 'zod'; const envSchema = z.object({ DATABASE_URL: z.string().url(), NEXTAUTH_SECRET: z.string().min(32), NODE_ENV: z.enum(['development', 'test', 'production']), PORT: z.coerce.number().default(3000), }); export const env = envSchema.parse(process.env); // env.PORT is now type `number`, not `string | undefined` ``` #### Generic Repository Pattern ```typescript interface Repository { findById(id: TId): Promise; findMany(filter?: Partial): Promise; create(data: Omit): Promise; update(id: TId, data: Partial>): Promise; delete(id: TId): Promise; } class UserRepository implements Repository { async findById(id: UserId) { /* ... */ } // TypeScript enforces all interface methods are implemented } ``` --- ### Common Pitfalls to Avoid | Anti-Pattern | Problem | Solution | |---|---|---| | `as any` | Disables type checking | Use `unknown` + narrowing or Zod | | `as Type` (unsafe cast) | Bypasses structural checking | Use type guards or `satisfies` | | `// @ts-ignore` | Silences real errors | Fix the root type issue | | `!` non-null assertion | Runtime errors if null | Use optional chaining + nullish coalescing | | `Object` / `{}` type | Accepts anything non-null | Use specific types or `Record` | | Implicit `any` in callbacks | Breaks type inference | Always type function parameters | --- ### The `satisfies` Operator (TS 4.9+) ```typescript // Validates against a type without widening the inferred type const config = { port: 3000, host: 'localhost', debug: true, } satisfies Record; // config.port is still inferred as `3000` (literal), not `number` config.port.toFixed(2); // Works! Literal type preserved. ``` ### Sovereign Execution, Token Efficiency & Invariants | Dimension | Sovereign Mandate & Deterministic Contract | | :--- | :--- | | **Frontier Model Cascade** | Medium / High (`GPT-5.6 Sol Medium`, `Gemini 4 Argon`, `Claude Sonnet 5.5 High`, `Grok 4.7 High Fast`) | | **Availability Fallback** | `Gemini 4 Argon/Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6` (Zero unhandled missing-model errors) | | **KV-Cache & Token Protocol** | Pin static instructions & schemas at prompt prefix (`kv-cache-prefix-optimizer`); pass surgical `CONTEXT_MAP.md` slices (<250 tokens/call) during Swarm Fan-Out | | **SaaT CLI & MCP Dispatch** | CLI: `vibes skill exec typescript-expert ` / MCP: `vibes_skill_dispatch`, `vibes_ast_query`, `vibes_compile_cache`, `vibes_optimize_budget`, `vibes_verify_gate` | | **NFR & Anti-Slop Invariants** | P99 API Gateway Latency < 85ms, OpenAPI 3.1 / TypeSpec strict schema parity, RFC 9457 Problem Details error contracts, Idempotency-Key enforcement; 100% complete zero-placeholder output verified via `node scripts/check-anti-slop.js --strict` | --- --- ## Bahasa Indonesia ### Integrasi Orkestrasi - **Hulu & Pondasi**: `zero-to-prod-orchestrator` (Pondasi Fase 2), `brainstorming`, `session-memory-manager`. - **AST & Inteligensi Basis Kode**: `living-codebase-ast-graph` (compiler API & simbol type-checker), `scalability-clean-code` (pola clean type-safe). - **Runtime Backend & Fullstack**: `js-backend-expert` (tipe ketat Node.js/Bun), `database-orm-expert` (generasi tipe skema Prisma/Drizzle). - **Frontend & Monorepo**: `senior-frontend` (type safety React 19), `monorepo-architect` (composite project & isolated declarations), `form-validation-expert` (inferensi skema Zod). ### Deskripsi Panduan TypeScript level ahli mencakup sistem tipe tingkat lanjut, penerapan strict mode, pemrograman generik, utility types, branded types, dan pola type-safe untuk aplikasi produksi. Menargetkan fitur **TypeScript 5.8+** termasuk inferred type predicates, isolated declarations, `NoInfer`, deklarasi `using`, peningkatan variadic tuple, dan parameter tipe `const`. ### Kondisi Pemicu - Menulis TypeScript dengan generic constraints tingkat lanjut. - Menerapkan type safety ketat di codebase yang ada. - Merancang kontrak API type-safe (REST, tRPC, Zod schema). - Mengimplementasikan branded types untuk pemodelan domain. - Menyelesaikan type error kompleks atau polusi `any`. - Menyiapkan `tsconfig.json` untuk proyek strict dengan `isolatedDeclarations`. - Menulis utility types atau type helpers TypeScript. ### Panduan Singkat - **Aktifkan strict mode**: Selalu gunakan `"strict": true` ditambah `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, dan `isolatedDeclarations`. - **Inferred Type Predicates** (TS 5.5): Filter array tanpa type assertion manual — TypeScript inferensikan sendiri. - **Isolated Declarations** (TS 5.5): Aktifkan untuk mempercepat build monorepo via parallel `.d.ts` generation. - **Branded Types**: Cegah pencampuran primitif yang berbeda secara semantis (UserId vs PostId). - **Discriminated Union**: Gunakan untuk state machine dan variant data yang terbatas. - **Zod**: Validasi data eksternal dan turunkan tipe TypeScript dari schema Zod. - **Hindari `as any`**: Gunakan `unknown` dengan narrowing atau Zod untuk data yang tidak diketahui tipenya. - **`satisfies` operator**: Validasi objek terhadap tipe tanpa melebarkan tipe yang diinferensi. - **`moduleResolution: Bundler`**: Gunakan untuk proyek Next.js/Vite; `NodeNext` untuk Node.js/Bun backend. ### Matriks Eksekusi Berdaulat, Efisiensi Token & Invarian | Dimensi | Mandat Berdaulat & Kontrak Deterministik | | :--- | :--- | | **Kaskade Model Frontier** | Medium / High (`GPT-5.6 Sol Medium`, `Gemini 4 Argon`, `Claude Sonnet 5.5 High`, `Grok 4.7 High Fast`) | | **Invarian Fallback Ketersediaan** | `Gemini 4 Argon/Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6` (Bebas gagal saat model belum tersedia/kuota penuh) | | **Protokol Hemat Token & KV-Cache** | Kunci instruksi & skema statis di prefix awal (`kv-cache-prefix-optimizer`); kirim potongan `CONTEXT_MAP.md` (<250 token/panggilan) saat Fan-Out | | **Eksekusi SaaT CLI & MCP** | CLI: `vibes skill exec typescript-expert ` / MCP: `vibes_skill_dispatch`, `vibes_ast_query`, `vibes_compile_cache`, `vibes_optimize_budget`, `vibes_verify_gate` | | **Invarian NFR & Anti-Slop** | Latensi P99 API < 85ms, paritas skema ketat OpenAPI 3.1 / TypeSpec, kontrak error RFC 9457 Problem Details, penegakan Idempotency-Key; kode 100% tuntas tanpa placeholder diverifikasi melalui `node scripts/check-anti-slop.js --strict` |