plugins/typescript-development/skills/typescript-write/SKILL.md
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).
npx skillsauth add acaprino/alfio-claude-plugins typescript-writeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
camelCase for variables, functions, parametersPascalCase for types, interfaces, classes, enums, React componentsUPPER_SNAKE_CASE for constants and enum membersI only if project convention requires it - otherwise plain PascalCaseis, has, should, can prefixes (isLoading, hasPermission)handleClick, onSubmit patternindex.ts) for public module APIs only - avoid deep barrel re-exportskebab-case.ts for utilities, PascalCase.tsx for React componentsnode:fs, node:path)react, lodash)@/utils, @/components)./helpers, ../types)import type { Foo })strict: true in tsconfig.json - never disable individual strict checks// @ts-ignore or // @ts-expect-error without an explanatory commentunknown over any - narrow with type guardsany - use unknown and narrow, or define a proper typeinterface for object shapes that may be extendedtype for unions, intersections, mapped types, and utility typesreadonly for properties that should not be mutatedas const for literal type inference on objects and arraystype 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;
}
// 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`);
}
}
// 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;
};
Partial<T> - all properties optional (use for update/patch operations)Required<T> - all properties requiredPick<T, K> - select subset of propertiesOmit<T, K> - exclude propertiesRecord<K, V> - typed key-value mapExtract<T, U> / Exclude<T, U> - filter union memberstype Status = "active" | "inactive"const enum only if you need numeric values and tree-shakingenum when you need runtime reverse mapping or iteration// 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>;
}
use prefixuseCallback for functions passed as props to memoized childrenuseMemo for expensive computations - not for every variableuseReducer for complex state with multiple sub-values or transitions// Type event handlers properly
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setValue(e.target.value);
}
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
// ...
}
*.test.ts or *.spec.ts alongside the source file__tests__/ directory mirroring the source structuretest-utils.ts or testing/ directorydescribe("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();
});
});
toBe for primitives, toEqual for objects/arraystoThrow for error cases - wrap in arrow functiontoHaveBeenCalledWith for spy/mock assertionstoBeTruthy/toBeFalsyas any in testsvi.fn() (Vitest) or jest.fn() for function mocksvi.spyOn / jest.spyOn to mock methods while preserving type safetybeforeEach or use afterEach(() => vi.restoreAllMocks())any Instead of Proper Types// 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");
}
// BAD
const name = user!.name!;
// GOOD
if (!user?.name) throw new Error("User name required");
const name = user.name;
// BAD - importing everything through deep barrel
import { Button } from "@/components"; // pulls entire component tree
// GOOD - direct import
import { Button } from "@/components/Button";
// 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>;
}
// 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];
}
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();
return { ok: true, value: user };
} catch (e) {
return { ok: false, error: e instanceof Error ? e : new Error(String(e)) };
}
}
try/catch around await calls that can fail.catch() and await on the same promise chaincomponentDidCatchclass NotFoundError extends Error {
readonly code = "NOT_FOUND" as const;
constructor(resource: string, id: string) {
super(`${resource} ${id} not found`);
this.name = "NotFoundError";
}
}
class ValidationError extends Error {
readonly code = "VALIDATION" as const;
constructor(public readonly fields: Record<string, string>) {
super("Validation failed");
this.name = "ValidationError";
}
}
development
Unified web frontend knowledge base covering CSS architecture, UX psychology, UI components, distinctive aesthetics, and interface design generation. TRIGGER WHEN: working on web styling, design systems, component decisions, responsive strategy, distinctive frontend aesthetics, or exploring multiple interface designs. DO NOT TRIGGER WHEN: the task is purely backend or unrelated to web frontend.
development
Coordinate parallel code reviews across multiple quality dimensions with finding deduplication, severity calibration, and consolidated reporting. Use this skill when organizing multi-reviewer code reviews, calibrating finding severity, or consolidating review results.
tools
Knowledge base for the codebase-mapper plugin. Provides writing guidelines, tone rules, and diagram conventions for generating human-readable project guides. Referenced by all codebase-mapper agents during document generation. TRIGGER WHEN: referenced by codebase-mapper pipeline agents (codebase-explorer, overview-writer, tech-writer, flow-writer, onboarding-writer, ops-writer, config-writer, guide-reviewer) during document generation. DO NOT TRIGGER WHEN: outside the /map-codebase pipeline (general documentation work should use docs:readme-craft or codebase-mapper:docs-create).
tools
Progressive Web App knowledge base for 2025-2026: Web App Manifest, Service Workers (Workbox 7, Serwist), Web Push (VAPID, RFC 8030/8291/8292, Declarative Push for Safari 18.4+), install flows (beforeinstallprompt, Window Controls Overlay), OPFS storage, Project Fugu, Core Web Vitals (INP < 200ms), security (HTTPS, CSP, COOP/COEP), and distribution (Bubblewrap, PWA Builder MSIX, Capacitor). TRIGGER WHEN: building, auditing, or debugging PWAs, including manifest, service worker, Web Push, install flow, OPFS, Background Sync, Wake Lock, vite-plugin-pwa, Next.js Serwist, @angular/pwa, @vite-pwa/nuxt, Bubblewrap, TWA, PWA Builder, or Capacitor wrapping. DO NOT TRIGGER WHEN: the task is generic frontend styling (use frontend), React performance (use react-development:review-react), cross-platform security unrelated to PWA (use platform-engineering), Tauri or Electron wrappers (use tauri-development), or GA4 / analytics (use digital-marketing).