| name | typescript-style |
| description | Use when TypeScript or TSX work needs guidance on API shape, function signatures, exported contracts, strict typing, lint-safe escape hatches, or lightweight off-the-shelf library choices for JS/TS tools. |
TypeScript Style
Use this skill for generic TypeScript and TSX work. Keep React-specific rendering and hooks guidance in react-patterns, layout guidance in css-layout, and project-specific workflow guidance in the appropriate overlay skill when needed.
Tooling Defaults
- When a non-temporary JS/TS tool needs a small off-the-shelf library choice, use references/tooling-defaults.md.
- Keep those defaults short and pragmatic. Prefer built-ins when they are already direct and sufficient.
- For non-temporary JS/TS tools, prefer Bun, TypeScript, Oxlint,
@jackokerman/oxlint-config, and repo-local deterministic quality gates unless the surrounding project has a stronger established stack.
- For non-temporary Bun/TypeScript CLI tools that agents will edit or invoke repeatedly, add
slop-scan as part of the preferred validation stack; keep command shape and config policy in references/tooling-defaults.md.
- Put reusable lint style changes in
github.com/jackokerman/oxlint-config first. Release the config and update dependents only when the exported lint behavior changes; do not churn dependents for docs-only, README-only, or source-repo check-tooling releases.
- When creating or publishing a reusable npm package, use references/npm-package-release.md.
Code Shape And Defaults
- Prefer plain functions and typed objects over classes unless the surrounding code already uses class-heavy patterns.
- Prefer small focused functions. Use guard clauses and early returns to flatten control flow instead of nesting conditionals when a branch can exit early.
- Prefer
const by default and let only when reassignment is part of the logic.
- Prefer template literals over string concatenation when dynamic values are involved.
- For broad naming or API-shape migrations, use symbol-aware TypeScript refactors when practical, then separately audit serialized boundaries such as config keys, CLI flags, env vars, JSON payload fields, database fields, and persisted state before changing them.
- When adding tests around Bun-based CLI behavior, verify the configured test runner runtime before using Bun-specific globals in test code. If Vitest or another runner executes under Node, use Node APIs such as
node:child_process for process tests while still invoking the Bun CLI as the system under test.
API Shape And Types
- Prefer
type over interface unless you need extends, declaration merging, or the surrounding code already relies on interfaces.
- Prefer named exports over default exports unless the local module pattern is already established.
- When an API has more than one or two related inputs, prefer a typed options object over a long positional parameter list.
- Keep API surfaces minimal. Do not add optional parameters, configuration flags, or customization hooks unless a real current caller needs them.
- Keep shared types close to the module that owns them. Extract only when they are reused or part of a public contract.
- For helpers, accept the smallest structural type that expresses what they need. Do not require a full generated object or a broad union when a narrower object shape is enough.
- For React components, extract props into a named
FooProps type instead of inlining a large object type in the component signature.
Functions And Parameters
- Prefer named function declarations for exported functions and module-level helpers when the surrounding API allows it.
- When a function takes an object parameter, destructure it at the boundary when that makes the contract clearer. This applies to React props and typed options objects.
- Use inline defaults at the boundary when they clarify the contract more than a fallback chain in the body.
Documentation
- Add JSDoc descriptions to exported functions, hooks, components, and types when they define a module contract or non-obvious behavior.
- If an exported component or function relies on a local props, options, or input type to define that contract, document that supporting type too even when the type itself is not exported.
- For prop, options, and input object types that back an exported API, add inline JSDoc to the individual fields when that hover text clarifies the contract or disambiguates similarly named props.
- For exported utility helpers in shared modules, prefer a short JSDoc sentence even when the implementation is small, especially if the helper mutates inputs or mirrors another library contract.
- When documenting functions or types, use JSDoc block comments (
/** ... */) instead of line comments.
- Always format JSDoc as a multiline block, even for a single sentence. Do not use the condensed single-line form
/** ... */.
- Write JSDoc prose as complete sentences with explicit subjects. Avoid clipped follow-on fragments when a phrase like
this queues one more pass is clearer.
- Skip
@param and @returns tags unless a specific tool requires them. The TypeScript signature already carries that information.
- Document nested object fields inline on the type when that is the clearest place to explain them.
- Focus documentation on exported and non-obvious code. Do not blanket-comment trivial local helpers.
Type Safety And Escapes
- Do not use
any. Exhaust unknown, generics, narrowing, overloads, or declaration files first. If you still believe any is necessary, surface that explicitly before adding it.
- Treat external or untrusted data as
unknown at the boundary, then narrow it deliberately.
- For optional values, prefer explicit strict checks such as
=== undefined or !== undefined over loose null checks.
- Prefer optional chaining and nullish coalescing when they make fallback logic clearer.
- Before weakening a shared lint config, verify the rule's documented options or local schema. If a legitimate exception has no narrow option and is domain-specific, prefer a small local suppression with a concrete reason over turning the rule off globally.
- If an inline
eslint-disable is necessary, add a short comment explaining why the escape hatch is safe.
- If several nearby lines need the same rule disabled, prefer a single file-level disable with a clear explanation over repeated identical
eslint-disable-next-line comments.