Skip to main content

typescript-expert

Solves TypeScript/JS problems and refactors TS for type safety: narrowing, branded types, deep-instantiation errors, strict tsconfig, module resolution, JS-to-TS migration.

Source facts

Repository
shipshitdev/skills
Last source activity
October 5, 2026 at 18:24
Detected SKILL.md language
English
Stars
37
Forks
3

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
59 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
typescript-expert
description
Solves TypeScript/JS problems and refactors TS for type safety: narrowing, branded types, deep-instantiation errors, strict tsconfig, module resolution, JS-to-TS migration.
metadata
{"portable_source":"https://github.com/ericlitman/open-pstack","portable_commit":"1b03678171f6f400ae2cc9dc4e7a4a6a13e4bb43","category":"framework","risk":"critical","date_added":"2026-02-27","version":"2.2.2","tags":"typescript, javascript, tooling"}
when_to_use
type performance, monorepo config, satisfies, branded types, remove as casts
# TypeScript Expert ## When invoked 1. Analyze project setup comprehensively: **Prefer built-in file-reading and search capabilities for performance. Shell commands are fallbacks.** ```bash # 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|jest|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 2. Identify the specific problem category and complexity level 3. Apply the appropriate solution strategy from the expertise below 4. Validate thoroughly: ```bash # 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 build ``` **Safety 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`](references/rules/arch-discriminated-unions.md) — Use discriminated unions over string enums for exhaustive pattern matching - [`arch-branded-types`](references/rules/arch-branded-types.md) — Use branded types for domain identifiers to prevent value mix-ups - [`arch-satisfies-over-annotation`](references/rules/arch-satisfies-over-annotation.md) — Use `satisfies` for config objects to preserve literal types - [`arch-interfaces-over-intersections`](references/rules/arch-interfaces-over-intersections.md) — Extend interfaces instead of intersecting types for better error messages - [`arch-const-assertion`](references/rules/arch-const-assertion.md) — Use `as const` for immutable literal inference - [`arch-readonly-by-default`](references/rules/arch-readonly-by-default.md) — Default to readonly types for function parameters and return values - [`arch-avoid-partial-abuse`](references/rules/arch-avoid-partial-abuse.md) — Avoid `Partial<T>` abuse for builder patterns #### 2. Type Narrowing & Guards (CRITICAL) - [`narrow-custom-type-guards`](references/rules/narrow-custom-type-guards.md) — Write custom type guards instead of type assertions - [`narrow-assertion-functions`](references/rules/narrow-assertion-functions.md) — Use assertion functions for precondition checks - [`narrow-exhaustive-switch`](references/rules/narrow-exhaustive-switch.md) — Enforce exhaustive switch with `never` - [`narrow-in-operator`](references/rules/narrow-in-operator.md) — Narrow with the `in` operator for interface unions - [`narrow-eliminate-as-casts`](references/rules/narrow-eliminate-as-casts.md) — Eliminate `as` casts with proper narrowing chains - [`narrow-typeof-chains`](references/rules/narrow-typeof-chains.md) — Use `typeof` narrowing before property access #### 3. Modern TypeScript (HIGH) - [`modern-using-keyword`](references/rules/modern-using-keyword.md) — Use the `using` keyword for resource cleanup - [`modern-const-type-parameters`](references/rules/modern-const-type-parameters.md) — Use const type parameters for literal inference - [`modern-template-literal-types`](references/rules/modern-template-literal-types.md) — Use template literal types for string patterns - [`modern-noinfer-utility`](references/rules/modern-noinfer-utility.md) — Use `NoInfer` to control type parameter inference - [`modern-accessor-keyword`](references/rules/modern-accessor-keyword.md) — Use `accessor` for auto-generated getters and setters - [`modern-verbatim-module-syntax`](references/rules/modern-verbatim-module-syntax.md) — Enable `verbatimModuleSyntax` for explicit import types #### 4. Generic Patterns (HIGH) - [`generic-infer-over-annotate`](references/rules/generic-infer-over-annotate.md) — Let TypeScript infer instead of explicit annotation - [`generic-constrain-dont-overconstrain`](references/rules/generic-constrain-dont-overconstrain.md) — Constrain generics minimally - [`generic-avoid-distributive-surprises`](references/rules/generic-avoid-distributive-surprises.md) — Control distributive conditional types - [`generic-mapped-type-utilities`](references/rules/generic-mapped-type-utilities.md) — Build custom mapped types for repeated transformations - [`generic-return-type-inference`](references/rules/generic-return-type-inference.md) — Preserve return type inference in generic functions #### 5. Compiler Performance (MEDIUM-HIGH) - [`compile-explicit-return-types`](references/rules/compile-explicit-return-types.md) — Add explicit return types to exported functions - [`compile-avoid-deep-recursion`](references/rules/compile-avoid-deep-recursion.md) — Avoid deeply recursive type definitions - [`compile-project-references`](references/rules/compile-project-references.md) — Use project references for monorepo builds - [`compile-base-types-over-unions`](references/rules/compile-base-types-over-unions.md) — Use base types instead of large union types #### 6. Error Safety (MEDIUM) - [`error-result-type`](references/rules/error-result-type.md) — Use Result types instead of thrown exceptions - [`error-exhaustive-error-handling`](references/rules/error-exhaustive-error-handling.md) — Use exhaustive checks for typed error variants - [`error-typed-catch`](references/rules/error-typed-catch.md) — Type catch clause variables as `unknown` - [`error-never-for-unreachable`](references/rules/error-never-for-unreachable.md) — Use `never` to mark unreachable code paths - [`error-discriminated-error-unions`](references/rules/error-discriminated-error-unions.md) — Model domain errors as discriminated unions #### 7. Runtime Patterns (MEDIUM) - [`perf-union-literals-over-enums`](references/rules/perf-union-literals-over-enums.md) — Use union literals instead of enums - [`perf-avoid-delete-operator`](references/rules/perf-avoid-delete-operator.md) — Avoid the `delete` operator on objects - [`perf-object-freeze-const`](references/rules/perf-object-freeze-const.md) — Use `Object.freeze` with `as const` for true immutability - [`perf-object-keys-narrowing`](references/rules/perf-object-keys-narrowing.md) — Avoid `Object.keys` type widening - [`perf-map-set-over-object`](references/rules/perf-map-set-over-object.md) — Use `Map` and `Set` over plain objects for dynamic collections #### 8. Quirks & Pitfalls (LOW-MEDIUM) - [`quirk-excess-property-checks`](references/rules/quirk-excess-property-checks.md) — Understand excess property checks on object literals - [`quirk-empty-object-type`](references/rules/quirk-empty-object-type.md) — Avoid the `{}` type — it means non-nullish - [`quirk-type-widening-let`](references/rules/quirk-type-widening-let.md) — Prevent type widening with `let` declarations - [`quirk-variance-annotations`](references/rules/quirk-variance-annotations.md) — Use variance annotations for generic interfaces - [`quirk-structural-typing-escapes`](references/rules/quirk-structural-typing-escapes.md) — 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** ```bash 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: true` for library type checking only (often significantly improves performance on large projects, but avoid masking app typing issues) - Use `incremental: true` with `.tsbuildinfo` cache - Configure `include`/`exclude` precisely - 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](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) **"Excessive stack depth comparing types"** - Cause: Circular or deeply recursive types - Fix priority: limit recursion depth with conditional types; use `interface` extends instead of type intersection; simplify generic constraints ```typescript // 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: 1. Check `moduleResolution` matches your bundler 2. Verify `baseUrl` and `paths` alignment 3. For monorepos: Ensure workspace protocol (`workspace:*`) 4. 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
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub