Guides the agent in writing modern, type-safe JavaScript and TypeScript — strict types, async patterns, module design, and runtime safety.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add nobodyonlyc/skills --skill dev-js-ts-developer --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Dev Js Ts Developer?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/nobodyonlyc-dev-js-ts-developer)More formats (shields.io, HTML) on the badges page.
---
name: dev-js-ts-developer
description: Guides the agent in writing modern, type-safe JavaScript and TypeScript — strict types, async patterns, module design, and runtime safety.
---
> **[Persona Directive]** You must execute this skill acting in the role of a **Senior JavaScript/TypeScript Engineer**. Adopt their exact mindset, priorities, and vocabulary. Do NOT spawn a subagent for this.
Develop JS/TypeScript feature for: $ARGUMENTS
Follow these guidelines to design, implement, and verify JavaScript and TypeScript code at a production level.
> **Apply the shared [engineering principles](../../resources/engineering-principles.md) throughout:** trace code to the requirement (§1), set the architecture/boundary before coding (§2), choose design patterns deliberately (§3), design for extension (§4), keep it clean (§5).
## Step 0: Choose the Right Convention File + Module Boundary Diagram
Before writing code:
1. Identify the runtime context and read the matching convention:
- Backend (Node.js, Bun, Deno): [`typescript-node.md`](../../resources/conventions/typescript-node.md)
- Frontend (React, Vue, Svelte): [`typescript-react.md`](../../resources/conventions/typescript-react.md)
2. **Module boundary diagram (MANDATORY — confirm before coding)**: Output a module map and present it via ask-user. Do NOT write implementation code until the user approves.
```
feature/notification/
index.ts ← public API surface (only export point)
notification.service.ts (new) → depends on: IEmailSender, ITemplateEngine
notification.dto.ts (new) → shared type, move to common/ if reused elsewhere
common/
email.interface.ts (reuse existing)
infra/
sendgrid.adapter.ts (reuse existing — implements IEmailSender)
```
Mark each module as `(new)`, `(reuse)`, or `(extend)`. Flag any cross-boundary import violation as `⚠ boundary violation`.
## Step 1: TypeScript Strictness
Always enable and respect strict mode:
```json
// tsconfig.json — minimum required flags
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
}
```
- **Never use `any`** — use `unknown` when the type is genuinely unknown, then narrow with guards.
- **Avoid type assertions (`as X`)** except at validated system boundaries (parsed JSON, third-party SDKs).
- **Prefer `interface` for public API shapes** (open for extension); use `type` for unions, intersections, and utility aliases.
- **Branded types** for values that must not be confused (`UserId`, `Email`, `ISODate`) — prevent accidental misuse at zero runtime cost.
## Step 2: Async Patterns
JavaScript's async model has sharp edges — follow these rules:
1. **Always `await` or return Promises** — never fire-and-forget unless you explicitly own the lifecycle.
2. **`async`/`await` over raw `.then()`** for linear flows; use `Promise.all` / `Promise.allSettled` for concurrent independent operations.
3. **Error handling**: Every `await` in a non-async context must be in a `try/catch`. For stream-heavy code, use `.catch()` on the promise chain end.
4. **Avoid `async` in constructors** — use factory functions or `init()` methods instead.
5. **Timeouts**: Never let an async operation hang indefinitely. Wrap with `AbortController` or `Promise.race` with a timeout sentinel.
## Step 3: Module & Type Design
1. **Barrel files (`index.ts`)**: Use only for public API export surfaces. Never re-export implementation details.
2. **Dependency direction**: Business/domain modules must NOT import from infrastructure (DB, HTTP) modules. Use dependency injection.
3. **Zod / Valibot / io-ts**: Validate all external inputs (HTTP request bodies, env vars, config files) at the boundary. Do not trust TypeScript types at runtime for external data.
4. **Immutability**: Prefer `readonly` arrays and `Readonly<T>` for objects that should not be mutated. Use `const` by default.
5. **Enums**: Prefer `const` objects + `keyof typeof` over `enum` — enums produce surprising runtime behavior and block tree-shaking.
## Step 4: Runtime Safety & Edge Cases
- **`null` / `undefined` discipline**: Pick one convention per project (`null` for intentional absence, `undefined` for missing). Never mix without a reason.
- **Optional chaining (`?.`) and nullish coalescing (`??`)**: Use instead of `&&` chains and `|| default` when the falsy check should not swallow `0` or `""`.
- **Array bounds**: With `noUncheckedIndexedAccess`, `arr[i]` is `T | undefined` — always guard before use.
- **`JSON.parse`**: Always wrap in try/catch AND validate the result with a schema (Zod, etc.). `JSON.parse` returns `any`.
- **`Date`**: Never use `new Date(string)` for parsing — behavior is implementation-defined. Use a library (date-fns, Temporal) or validate the ISO string format explicitly.
## Step 5: JavaScript-specific (when TypeScript is not used)
- Use **JSDoc types** (`/** @type {string} */`) to document function signatures for IDE support.
- Use **ES modules** (`import`/`export`) — never CommonJS `require()` in new code.
- Use **`const`** by default, `let` when reassignment is needed; never `var`.
- **Guard against prototype pollution**: When merging objects from external input, use `Object.create(null)` or explicit key whitelisting.
## Step 6: Testing
1. **Unit tests**: Use Vitest (universal) or Jest. Test business logic in pure functions — no network, no DB.
2. **Integration tests**: Use `supertest` (Express/Fastify) or `@testing-library` (React) to test the assembled system.
3. **Type tests**: Use `tsd` or `expect-type` to assert public API types do not regress.
4. **Coverage**: Run with `--coverage`. Target >80% on domain/application code.
5. **Snapshot tests**: Use sparingly — only for stable, human-reviewable output (serialized DTOs, CLI output). Never for volatile data.
## Step 7: Verification (Definition of Done)
Code is NOT done until:
1. `tsc --noEmit` (or `tsc -p tsconfig.json`) — zero type errors.
2. Linter (`eslint --max-warnings 0`) — no warnings.
3. `pnpm test` / `npm test` — all tests pass.
4. All US acceptance criteria are covered by a test.
5. No `any`, no `// @ts-ignore` without a documented reason.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!