"Write TypeScript and JavaScript code following modern best practices and coding standards. TRIGGER WHEN: writing or reviewing TypeScript/JavaScript code." DO NOT TRIGGER WHEN: the task is outside the specific scope of this component.
npx claudepluginhub acaprino/alfio-claude-plugins --plugin typescript-developmentThis skill uses the workspace's default tool permissions.
- Writing new TypeScript or JavaScript files
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
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";
}
}