typescript-write
Write TypeScript and JavaScript code following modern best practices and coding standards. TRIGGER WHEN: writing or reviewing TypeScript/JavaScript code, including types, generics, async patterns, module boundaries, and style conventions. DO NOT TRIGGER WHEN: the task is framework-specific React performance (use react-development), Node.js build/packaging, or enterprise-grade deep-dive (use mastering-typescript skill).
What this skill does
# TypeScript/JavaScript Development Skill
## When to Invoke
- Writing new TypeScript or JavaScript files
- Refactoring existing TS/JS code
- Reviewing code for type safety and best practices
- Converting JavaScript to TypeScript
- Designing module APIs and type interfaces
- Fixing type errors or improving type coverage
## Code Style
### Naming Conventions
- `camelCase` for variables, functions, parameters
- `PascalCase` for types, interfaces, classes, enums, React components
- `UPPER_SNAKE_CASE` for constants and enum members
- Prefix interfaces with `I` only if project convention requires it - otherwise plain `PascalCase`
- Boolean variables: use `is`, `has`, `should`, `can` prefixes (`isLoading`, `hasPermission`)
- Event handlers: `handleClick`, `onSubmit` pattern
### File Organization
- One primary export per file when possible
- Group related types with their implementation
- Barrel exports (`index.ts`) for public module APIs only - avoid deep barrel re-exports
- File naming: `kebab-case.ts` for utilities, `PascalCase.tsx` for React components
### Import Ordering
1. Node built-in modules (`node:fs`, `node:path`)
2. External packages (`react`, `lodash`)
3. Internal aliases (`@/utils`, `@/components`)
4. Relative imports (`./helpers`, `../types`)
5. Type-only imports (`import type { Foo }`)
- Blank line between each group
## TypeScript Patterns
### Strict Mode
- Enable `strict: true` in `tsconfig.json` - never disable individual strict checks
- No `// @ts-ignore` or `// @ts-expect-error` without an explanatory comment
- Prefer `unknown` over `any` - narrow with type guards
### Proper Typing
- Avoid `any` - use `unknown` and narrow, or define a proper type
- Prefer `interface` for object shapes that may be extended
- Prefer `type` for unions, intersections, mapped types, and utility types
- Use `readonly` for properties that should not be mutated
- Use `as const` for literal type inference on objects and arrays
### Discriminated Unions
```typescript
type Result<T> =
| { success: true; data: T }
| { success: false; error: Error };
function handle<T>(result: Result<T>) {
if (result.success) {
// result.data is T here
return result.data;
}
// result.error is Error here
throw result.error;
}
```
### Type Guards
```typescript
// User-defined type guard
function isString(value: unknown): value is string {
return typeof value === "string";
}
// Assertion function
function assertDefined<T>(value: T | undefined, name: string): asserts value is T {
if (value === undefined) {
throw new Error(`Expected ${name} to be defined`);
}
}
```
### Generic Constraints
```typescript
// Constrain generics to what you actually need
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// Use defaults for common cases
type ApiResponse<T = unknown> = {
data: T;
status: number;
timestamp: string;
};
```
### Utility Types
- `Partial<T>` - all properties optional (use for update/patch operations)
- `Required<T>` - all properties required
- `Pick<T, K>` - select subset of properties
- `Omit<T, K>` - exclude properties
- `Record<K, V>` - typed key-value map
- `Extract<T, U>` / `Exclude<T, U>` - filter union members
- Prefer built-in utility types over manual type manipulation
### Enums vs Union Types
- Prefer string union types for simple sets: `type Status = "active" | "inactive"`
- Use `const enum` only if you need numeric values and tree-shaking
- Use regular `enum` when you need runtime reverse mapping or iteration
## React Patterns
### Component Typing
```typescript
// Function components - type props inline or with interface
interface ButtonProps {
label: string;
variant?: "primary" | "secondary";
onClick: () => void;
children?: React.ReactNode;
}
function Button({ label, variant = "primary", onClick, children }: ButtonProps) {
return <button className={variant} onClick={onClick}>{children ?? label}</button>;
}
```
### Hooks Rules
- Call hooks at the top level only - never inside conditions, loops, or nested functions
- Custom hooks must start with `use` prefix
- Specify dependency arrays accurately - never suppress exhaustive-deps lint
- Use `useCallback` for functions passed as props to memoized children
- Use `useMemo` for expensive computations - not for every variable
### State Management
- Colocate state as close to where it is used as possible
- Lift state up only when siblings need to share it
- Use `useReducer` for complex state with multiple sub-values or transitions
- Context for truly global state (theme, auth, locale) - not for frequently changing data
### Event Handling
```typescript
// Type event handlers properly
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setValue(e.target.value);
}
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
// ...
}
```
## Testing
### File Naming
- Test files: `*.test.ts` or `*.spec.ts` alongside the source file
- Or in `__tests__/` directory mirroring the source structure
- Test utilities: `test-utils.ts` or `testing/` directory
### Test Structure
```typescript
describe("calculateTotal", () => {
it("returns 0 for empty cart", () => {
expect(calculateTotal([])).toBe(0);
});
it("sums item prices with quantities", () => {
const items = [
{ price: 10, quantity: 2 },
{ price: 5, quantity: 1 },
];
expect(calculateTotal(items)).toBe(25);
});
it("throws for negative quantities", () => {
expect(() => calculateTotal([{ price: 10, quantity: -1 }])).toThrow();
});
});
```
### Assertion Patterns
- Use `toBe` for primitives, `toEqual` for objects/arrays
- Use `toThrow` for error cases - wrap in arrow function
- Use `toHaveBeenCalledWith` for spy/mock assertions
- Prefer specific matchers over generic `toBeTruthy`/`toBeFalsy`
- Type test fixtures and mocks - avoid `as any` in tests
### Mocking
- Mock external dependencies, not internal implementation
- Use `vi.fn()` (Vitest) or `jest.fn()` for function mocks
- Use `vi.spyOn` / `jest.spyOn` to mock methods while preserving type safety
- Reset mocks in `beforeEach` or use `afterEach(() => vi.restoreAllMocks())`
## Common Anti-Patterns
### Using `any` Instead of Proper Types
```typescript
// BAD
function parse(data: any) { return data.name; }
// GOOD
function parse(data: unknown): string {
if (typeof data === "object" && data !== null && "name" in data) {
return String((data as { name: unknown }).name);
}
throw new Error("Invalid data");
}
```
### Non-Null Assertion Overuse
```typescript
// BAD
const name = user!.name!;
// GOOD
if (!user?.name) throw new Error("User name required");
const name = user.name;
```
### Barrel File Performance Issues
```typescript
// BAD - importing everything through deep barrel
import { Button } from "@/components"; // pulls entire component tree
// GOOD - direct import
import { Button } from "@/components/Button";
```
### Ignoring Return Types
```typescript
// BAD - return type inferred as complex union
function getData(id: string) {
if (!id) return null;
return fetch(`/api/${id}`).then(r => r.json());
}
// GOOD - explicit return type
async function getData(id: string): Promise<ApiResponse | null> {
if (!id) return null;
const r = await fetch(`/api/${id}`);
return r.json() as Promise<ApiResponse>;
}
```
### Mutating Function Parameters
```typescript
// BAD
function addItem(items: Item[], item: Item) {
items.push(item); // mutates input
return items;
}
// GOOD
function addItem(items: readonly Item[], item: Item): Item[] {
return [...items, item];
}
```
## Error Handling
### Result Pattern
```typescript
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
async function fetchUser(id: string): Promise<Result<User>> {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) return { ok: false, error: new Error(`HTTP ${res.status}`) };
const user = await res.json();
rRelated in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.