About typescript-expert
A TypeScript-focused skill for developers working on project diagnosis, type-safe implementation, refactoring, and performance. It combines a project-aware workflow with detailed rules and reference guides.
Key features
- 01Project and tooling analysis
- 02Advanced type-system patterns
- 0343-rule refactoring library
- 04Type-checking and build optimization
- 05JavaScript-to-TypeScript migration guidance
Use cases
- 01Adapting changes to an existing TypeScript setup
- 02Refactoring casts into safer type narrowing
- 03Investigating slow type checking
- 04Planning an incremental JavaScript migration
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ shipshitdev/ skills --skill typescript-expertAfter installing, type/typescript-expertin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
plugin.jsonREADME.mdlicenses/LICENSELICENSE-cursor-team-kitLICENSE-superpowersNOTICE.txtreferences/full-guide.mdpatterns.mdreferences/rules/_sections.md_template.mdarch-avoid-partial-abuse.mdarch-branded-types.mdarch-const-assertion.mdarch-discriminated-unions.mdarch-interfaces-over-intersections.mdarch-readonly-by-default.mdarch-satisfies-over-annotation.mdcompile-avoid-deep-recursion.mdcompile-base-types-over-unions.mdcompile-explicit-return-types.mdcompile-project-references.mderror-discriminated-error-unions.mderror-exhaustive-error-handling.mderror-never-for-unreachable.mderror-result-type.mderror-typed-catch.mdgeneric-avoid-distributive-surprises.mdgeneric-constrain-dont-overconstrain.mdgeneric-infer-over-annotate.mdgeneric-mapped-type-utilities.mdDetails
From the project READMETypeScript Expert
When invoked
-
Analyze project setup comprehensively:
Prefer built-in file-reading and search capabilities for performance. Shell commands are fallbacks.
# Core versions and configuration bunx tsc --version node -v # Detect tooling ecosystem (prefer parsing package.json) node -e "const p=require('./package.json');console.log(Object.keys({...p.devDependencies,...p.dependencies}||{}).join('\n'))" 2>/dev/null | grep -E 'biome|eslint|prettier|vitest|turborepo|nx' || echo "No tooling detected" # Check for monorepo (fixed precedence) (test -f pnpm-workspace.yaml || test -f lerna.json || test -f nx.json || test -f turbo.json) && echo "Monorepo detected"After detection, adapt approach:
- Match import style (absolute vs relative)
- Respect existing baseUrl/paths configuration
- Prefer existing project scripts over raw tools
- In monorepos, consider project references before broad tsconfig changes
-
Identify the specific problem category and complexity level
-
Apply the appropriate solution strategy from the expertise below
-
Validate thoroughly:
# Fast fail approach (avoid long-lived processes) bun run typecheck || bunx tsc --noEmit bun run test || bunx vitest run --reporter=basic --no-watch # Only if needed and build affects outputs/config bun run buildSafety note: Avoid watch/serve processes in validation. Use one-shot diagnostics only.
Advanced Type System Expertise
Type-Level Programming Patterns
Branded Types for Domain Modeling — nominal types (type UserId = Brand<string, 'UserId'>) prevent accidentally mixing domain primitives that share a base type. Use for critical domain primitives, API boundaries, currency/units. Rule: references/rules/arch-branded-types.md; cheatsheet: references/typescript-cheatsheet.md (§ Branded Types). Resource: https://egghead.io/blog/using-branded-types-in-typescript
Advanced Conditional Types — recursive type manipulation (e.g. DeepReadonly<T>) and template-literal event-source APIs. Use for library APIs, type-safe event systems, compile-time validation. Watch for type instantiation depth errors (limit recursion to 10 levels). See references/typescript-cheatsheet.md (§ Conditional Types, § Mapped Types, § Template Literal Types) and references/rules/compile-avoid-deep-recursion.md.
Type Inference Techniques — use satisfies (TS 5.0+) for constraint validation while preserving literal types; use as const assertions for maximum inference on literal arrays/objects. Rules: references/rules/arch-satisfies-over-annotation.md, references/rules/arch-const-assertion.md.
Refactoring Rules
Refactoring or modernizing TypeScript for type safety (replacing as casts with narrowing, discriminated unions over enums, typed error handling, TS 4.x-5.x features, compile speed) draws on a 43-rule library in references/rules/. Open only the rules that apply, one file per rule. references/rules/_sections.md defines the categories and _template.md the shape of a new rule.
| Priority | Category | Prefix |
|---|---|---|
| 1 | Type Architecture (CRITICAL) | arch- |
| 2 | Type Narrowing & Guards (CRITICAL) | narrow- |
| 3 | Modern TypeScript (HIGH) | modern- |
| 4 | Generic Patterns (HIGH) | generic- |
| 5 | Compiler Performance (MEDIUM-HIGH) | compile- |
| 6 | Error Safety (MEDIUM) | error- |
| 7 | Runtime Patterns (MEDIUM) | perf- |
| 8 | Quirks & Pitfalls (LOW-MEDIUM) | quirk- |
1. Type Architecture (CRITICAL)
arch-discriminated-unions— Use discriminated unions over string enums for exhaustive pattern matchingarch-branded-types— Use branded types for domain identifiers to prevent value mix-upsarch-satisfies-over-annotation— Usesatisfiesfor config objects to preserve literal typesarch-interfaces-over-intersections— Extend interfaces instead of intersecting types for better error messagesarch-const-assertion— Useas constfor immutable literal inferencearch-readonly-by-default— Default to readonly types for function parameters and return valuesarch-avoid-partial-abuse— AvoidPartial<T>abuse for builder patterns
2. Type Narrowing & Guards (CRITICAL)
narrow-custom-type-guards— Write custom type guards instead of type assertionsnarrow-assertion-functions— Use assertion functions for precondition checksnarrow-exhaustive-switch— Enforce exhaustive switch withnevernarrow-in-operator— Narrow with theinoperator for interface unionsnarrow-eliminate-as-casts— Eliminateascasts with proper narrowing chainsnarrow-typeof-chains— Usetypeofnarrowing before property access
3. Modern TypeScript (HIGH)
modern-using-keyword— Use theusingkeyword for resource cleanupmodern-const-type-parameters— Use const type parameters for literal inferencemodern-template-literal-types— Use template literal types for string patternsmodern-noinfer-utility— UseNoInferto control type parameter inferencemodern-accessor-keyword— Useaccessorfor auto-generated getters and settersmodern-verbatim-module-syntax— EnableverbatimModuleSyntaxfor explicit import types
4. Generic Patterns (HIGH)
generic-infer-over-annotate— Let TypeScript infer instead of explicit annotationgeneric-constrain-dont-overconstrain— Constrain generics minimallygeneric-avoid-distributive-surprises— Control distributive conditional typesgeneric-mapped-type-utilities— Build custom mapped types for repeated transformationsgeneric-return-type-inference— Preserve return type inference in generic functions
5. Compiler Performance (MEDIUM-HIGH)
compile-explicit-return-types— Add explicit return types to exported functionscompile-avoid-deep-recursion— Avoid deeply recursive type definitionscompile-project-references— Use project references for monorepo buildscompile-base-types-over-unions— Use base types instead of large union types
6. Error Safety (MEDIUM)
error-result-type— Use Result types instead of thrown exceptionserror-exhaustive-error-handling— Use exhaustive checks for typed error variantserror-typed-catch— Type catch clause variables asunknownerror-never-for-unreachable— Useneverto mark unreachable code pathserror-discriminated-error-unions— Model domain errors as discriminated unions
7. Runtime Patterns (MEDIUM)
perf-union-literals-over-enums— Use union literals instead of enumsperf-avoid-delete-operator— Avoid thedeleteoperator on objectsperf-object-freeze-const— UseObject.freezewithas constfor true immutabilityperf-object-keys-narrowing— AvoidObject.keystype wideningperf-map-set-over-object— UseMapandSetover plain objects for dynamic collections
8. Quirks & Pitfalls (LOW-MEDIUM)
quirk-excess-property-checks— Understand excess property checks on object literalsquirk-empty-object-type— Avoid the{}type — it means non-nullishquirk-type-widening-let— Prevent type widening withletdeclarationsquirk-variance-annotations— Use variance annotations for generic interfacesquirk-structural-typing-escapes— Guard against structural typing escape hatches
Behavior-preserving restructuring stays with the refactor-code skill; it loads these rules for type-architecture work.
Performance Optimization Strategies
Type Checking Performance
bunx tsc --extendedDiagnostics --incremental false | grep -E "Check time|Files:|Lines:|Nodes:"
Common fixes for "Type instantiation is excessively deep": replace type intersections with interfaces (references/rules/arch-interfaces-over-intersections.md), split large union types (>100 members; references/rules/compile-base-types-over-unions.md), avoid circular generic constraints, use type aliases to break recursion. Add explicit return types to exported functions (references/rules/compile-explicit-return-types.md).
Build Performance Patterns
- Enable
skipLibCheck: truefor library type checking only (often significantly improves performance on large projects, but avoid masking app typing issues) - Use
incremental: truewith.tsbuildinfocache - Configure
include/excludeprecisely - For monorepos: Use project references with
composite: true(references/rules/compile-project-references.md)
Real-World Problem Resolution
Complex Error Patterns
"The inferred type of X cannot be named"
- Cause: Missing type export or circular dependency
- Fix priority: export the required type explicitly; use
ReturnType<typeof function>helper; break circular dependencies with type-only imports - Resource: https://github.com/microsoft/TypeScript/issues/47663
Missing type declarations — add an ambient .d.ts module declaration for untyped packages. See references/typescript-cheatsheet.md (§ Module Declarations). For more detail: Declaration Files Guide
"Excessive stack depth comparing types"
- Cause: Circular or deeply recursive types
- Fix priority: limit recursion depth with conditional types; use
interfaceextends instead of type intersection; simplify generic constraints
// Bad: Infinite recursion
type InfiniteArray<T> = T | InfiniteArray<T>[];
// Good: Limited recursion
type NestedArray<T, D extends number = 5> =
D extends 0 ? T : T | NestedArray<T, [-1, 0, 1, 2, 3, 4][D]>[];
Module Resolution Mysteries — "Cannot find module" despite the file existing:
- Check
moduleResolutionmatches your bundler - Verify
baseUrlandpathsalignment - For monorepos: Ensure workspace protocol (
workspace:*) - Try clearing cache:
rm -rf node_modules/.cache .tsbuildinfo
Path Mapping at Runtime — TypeScript paths only work at compile time, not runtime:
- ts-node: use
ts-node -r tsconfig-paths/register - Node ESM: use loader alternatives or avoid TS paths at runtime
- Production: pre-compile with resolved paths
Migration Expertise
JavaScript to TypeScript Migration — incremental strategy: enable allowJs/checkJs in the existing tsconfig, rename files gradually (.js → .ts), add types file by file, enable strict mode features one by one. See references/full-guide.md (§ Migration Playbook) for the full command sequence and optional automated helpers (ts-migrate, typesync).
Tool Migration Decisions
| From | To | When | Migration Effort |
|---|---|---|---|
| ESLint + Prettier | Biome | Need much faster speed, okay with fewer rules | Low (1 day) |
| TSC for linting | Type-check only | Have 100+ files, need faster feedback | Medium (2-3 days) |
| Lerna | Nx/Turborepo | Need caching, parallel builds | High (1 week) |
| CJS | ESM | Node 18+, modern tooling | High (varies) |
Monorepo Management
Nx vs Turborepo Decision Matrix
- Choose Turborepo if: Simple structure, need speed, <20 packages
- Choose Nx if: Complex dependencies, need visualization, plugins required
- Performance: Nx often performs better on large monorepos (>50 packages)
TypeScript Monorepo Configuration — root tsconfig references array plus composite/declaration/declarationMap per package. See references/full-guide.md (§ Monorepo TypeScript Configuration) for the full config.
Modern Tooling Expertise
Biome vs ESLint
Use Biome when: speed is critical, want a single tool for lint + format, TypeScript-first project, okay with 64 TS rules vs 100+ in typescript-eslint.
Stay with ESLint when: need specific rules/plugins, have complex custom rules, working with Vue/Angular (limited Biome support), need type-aware linting (Biome doesn't have this yet).
Type Testing Strategies
Vitest Type Testing (Recommended) — write .test-d.ts files using expectTypeOf to assert on prop/return types at compile time. See references/full-guide.md (§ Vitest Type Testing) for a full example.
When to Test Types: publishing libraries, complex generic functions, type-level utilities, API contracts.
Debugging Mastery
CLI Debugging Tools — trace module resolution (tsc --traceResolution), profile type-check performance (tsc --generateTrace), debug files directly with tsx/ts-node --inspect-brk. See references/full-guide.md (§ CLI Debugging Tools) for the full command set.
Custom Error Classes — extend Error, set this.name, and call Error.captureStackTrace to preserve the stack. See references/full-guide.md (§ Custom Error Classes) for the full pattern.
Current Best Practices
Strict by Default
Use strict: true plus noUncheckedIndexedAccess, noImplicitOverride, exactOptionalPropertyTypes, noPropertyAccessFromIndexSignature. See references/tsconfig-strict.json for a full production-ready strict config.
ESM-First Approach
- Set
"type": "module"in package.json - Use
.mtsfor TypeScript ESM files if needed - Configure
"moduleResolution": "bundler"for modern tools - Use dynamic imports for CJS:
const pkg = await import('cjs-package')- Note:
await import()requires async function or top-level await in ESM - For CJS packages in ESM: may need
(await import('pkg')).defaultdepending on the package's export structure and compiler settings
- Note:
AI-Assisted Development
- AI coding assistants excel at TypeScript generics and boilerplate type definitions
- Validate AI-generated types with type tests
- Document complex types for AI context
Code Review Checklist
Type Safety
- No implicit
anytypes (useunknownor proper types) - Strict null checks enabled and properly handled
- Type assertions (
as) justified and minimal - Generic constraints properly defined
- Discriminated unions for error handling
- Return types explicitly declared for public APIs
TypeScript Best Practices
- Prefer
interfaceovertypefor object shapes (better error messages) - Use const assertions for literal types
- Leverage type guards and predicates
- Avoid type gymnastics when simpler solution exists
- Template literal types used appropriately
- Branded types for domain primitives
Performance Considerations
- Type complexity doesn't cause slow compilation
- No excessive type instantiation depth
- Avoid complex mapped types in hot paths
- Use
skipLibCheck: truein tsconfig - Project references configured for monorepos
Module System
- Consistent import/export patterns, no circular dependencies
- Proper use of barrel exports (avoid over-bundling)
- ESM/CJS compatibility handled correctly, dynamic imports for code splitting
Error Handling Patterns
- Result types or discriminated unions for errors (
references/rules/error-*.md) - Custom error classes with proper inheritance, type-safe error boundaries
- Exhaustive switch cases with
nevertype
Code Organization
- Types co-located with implementation
- Shared types in dedicated modules
- Avoid global type augmentation when possible
- Proper use of declaration files (.d.ts)
Quick Decision Trees
"Which tool should I use?"
Type checking only? → tsc
Type checking + linting speed critical? → Biome
Type checking + comprehensive linting? → ESLint + typescript-eslint
Type testing? → Vitest expectTypeOf
Build tool? → Project size <10 packages? Turborepo. Else? Nx
"How do I fix this performance issue?"
Slow type checking? → skipLibCheck, incremental, project references
Slow builds? → Check bundler config, enable caching
Slow tests? → Vitest with threads, avoid type checking in tests
Slow language server? → Exclude node_modules, limit files in tsconfig
Expert Resources
- Performance: TypeScript Wiki Performance, Type instantiation tracking
- Advanced patterns: Type Challenges, Type-Level TypeScript Course
- Tools: Biome (linter/formatter), TypeStat (auto-fix types), ts-migrate (migration toolkit)
- Testing: Vitest Type Testing, tsd (standalone type testing)
Always validate changes don't break existing functionality before considering the issue resolved.
Typescript Best Practices procedure
Read typescript-best-practices procedure when running this workflow. Apply the authorized scope and mode of this entry point to every step. Resolve other skills through this distribution’s active catalog; resolve resources relative to the installed skill directory.