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/anvil-toolset 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";
}
}
tools
Master memory forensics techniques including memory acquisition, process analysis, and artifact extraction using Volatility and related tools. Use when analyzing memory dumps, investigating incidents, or performing malware analysis from RAM captures.
development
Master binary analysis patterns including disassembly, decompilation, control flow analysis, and code pattern recognition. Use when analyzing executables, understanding compiled code, or performing static analysis on binaries.
development
Idiomatic Kotlin implementation patterns: coroutines and structured concurrency, Flow / StateFlow / SharedFlow, Kotlin Multiplatform (KMP) shared-code architecture, Jetpack Compose UI, Ktor server with JWT auth and Exposed, and type-safe DSL design (lambdas with receivers, delegated properties, inline reified, value classes). TRIGGER WHEN: building, writing, or reviewing Kotlin code using coroutines / Flow / suspend functions, expect/actual, Compose composables / ViewModels, Ktor routing, sealed-class state modeling, scope functions, or DSL builders. DO NOT TRIGGER WHEN: libGDX game work (use libgdx-development), Android Java without Kotlin, or pure JVM tuning unrelated to Kotlin language features.
tools
Strategic website planning skill that conducts structured client discovery, produces professional deliverables (website brief, sitemap, design direction, content strategy), and orchestrates frontend-design, frontend-layout, seo-specialist, and content-marketer agents automatically. TRIGGER WHEN: planning a new website or redesign before any code is written. DO NOT TRIGGER WHEN: the task is outside the specific scope of this component.