Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions skills/typescript-patterns/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: typescript-patterns
description: TypeScript best practices, type safety, generics, async patterns, and project configuration for Claude Code and Codex.
---
Comment on lines +1 to +4

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the published skill counts before adding this file

Because npm test runs node scripts/ci/catalog.js --text (package.json:107), adding this 116th skill without updating the documented totals makes the default validation fail for every branch that includes this commit. Running the catalog check on top of this change reports skills: 116 while README.md and AGENTS.md still advertise 115, so CI will stay red until those counts are bumped.

Useful? React with 👍 / 👎.

Comment on lines +1 to +4

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add this skill to the TypeScript install manifests

This new skill is not wired into any install path yet. Manifest-driven installs only copy entries from module.paths (scripts/lib/install-targets/helpers.js:260-277), lang:typescript still resolves via framework-language (manifests/install-components.json:53-58), and that module does not include skills/typescript-patterns (manifests/install-modules.json:105-138). In practice, users who install the TypeScript bundle—e.g. via npx ecc typescript—won't receive the skill you added here.

Useful? React with 👍 / 👎.


# TypeScript Patterns

## When to Use
- Working with TypeScript projects
- Adding type safety to JavaScript code
- Configuring tsconfig.json
- Using generics, utility types, or advanced type features

## How It Works
1. Apply strict TypeScript configuration
2. Use proper type annotations and inference
3. Leverage generics for reusable components
4. Handle async/await with proper error types

## Key Patterns

### Strict Configuration
Always enable strict mode in tsconfig.json: strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes.

### Type-Safe Error Handling
Use discriminated unions for error types instead of throwing. Return Result types for fallible operations.

### Generic Constraints
Constrain generics with extends to ensure type safety while maintaining flexibility.

### Async Patterns
Use async/await with typed catch blocks. Prefer Promise.allSettled over Promise.all for parallel operations that can partially fail.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

In modern TypeScript, can catch clause variables be explicitly type-annotated (other than any/unknown), and what is the recommended pattern for catch error handling?

💡 Result:

No, in modern TypeScript, catch clause variables cannot be explicitly type-annotated with types other than 'any' or 'unknown'. Attempting to use any other specific type (like Error or a custom type) results in the compiler error TS1196: "Catch clause variable type annotation must be 'any' or 'unknown' if specified." This restriction exists because JavaScript can throw values of any type (not just Error objects), and TypeScript cannot statically verify what will be thrown. TypeScript 4.0 introduced support for annotating catch variables as 'unknown' (safer than 'any'), and TypeScript 4.4 added the tsconfig option 'useUnknownInCatchVariables' (part of strict mode) to make unannotated catch variables default to 'unknown' instead of 'any'. The recommended pattern for catch error handling is: 1. Use 'catch (error: unknown)' or enable 'useUnknownInCatchVariables' so unannotated variables are 'unknown'. 2. Use type guards (instanceof Error, property checks, or custom type predicates) to narrow the type before accessing properties. 3. Avoid type assertions unless necessary, as they bypass safety. Example: try { riskyOperation; } catch (error: unknown) { if (error instanceof Error) { console.error(error.message); // Safe: error is Error } else { console.error('Unknown error:', error); } } Utility helper pattern (common best practice): function getErrorMessage(error: unknown): string { if (error instanceof Error) return error.message; return String(error); } This ensures type safety while handling any thrown value. For domain-specific errors, throw custom Error subclasses and check with instanceof.

Citations:


Clarify catch block error handling guidance for TypeScript accuracy.

Line 32 states "Use async/await with typed catch blocks," but this wording is ambiguous and could suggest explicit catch-parameter typing is a standard pattern. Rephrase to "use unknown in catch parameters and narrow the type before use" to align with TypeScript's actual capabilities (catch variables can only be annotated as any or unknown). This ensures developers understand the proper pattern: catch with unknown, then narrow via type guards (instanceof checks, property validation) before accessing error properties.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@skills/typescript-patterns/SKILL.md` at line 32, Replace the ambiguous
guidance "Use async/await with typed catch blocks" in SKILL.md with a precise
instruction to use `unknown` for catch parameters and then narrow the error
before use (via instanceof, custom type guards, or property checks); update the
surrounding sentence to explicitly state that catch variables should be treated
as unknown and narrowed rather than annotated with a concrete type, and keep the
existing advice to prefer Promise.allSettled for parallel operations that can
partially fail.


### Utility Types
Use Pick, Omit, Partial, Required, Record for type transformations instead of manual type definitions.

## Examples
- Use zod for runtime validation that generates TypeScript types
- Prefer const assertions for literal types
- Use satisfies operator for type checking without widening
Loading