Agent skill
typescript-standards
TypeScript coding standards for Oh My Brand! theme. Strict mode, interfaces, type definitions, classes, DOM manipulation, and patterns. Use when writing TypeScript components, utilities, or Web Components.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/typescript-standards-wesleysmits-oh-my-brand-wp-fse-7353b04c
Metadata
Additional technical details for this skill
- author
- Wesley Smits
- version
- 1.0.0
SKILL.md
TypeScript Standards
TypeScript coding standards and patterns for the Oh My Brand! WordPress FSE theme.
When to Use
- Writing TypeScript components or utilities
- Creating Web Components for block frontends
- Building editor components (
edit.tsx) - Working with DOM manipulation
- Defining type interfaces
Reference Files
| File | Purpose |
|---|---|
| GalleryCarousel-example.ts | Full class example (~110 lines) |
| utility-functions.ts | Debounce/throttle utilities (~60 lines) |
File Structure
/**
* Module description.
*/
// Imports - external first, then internal
import { someFunction } from 'external-library';
import { helperFunction } from '../utils/helper';
// Types and interfaces
interface ComponentOptions {
readonly selector: string;
animationDuration?: number;
}
// Constants
const DEFAULT_DURATION = 300;
// Main implementation
export class ComponentName { }
// Module initialization
export function initComponent(): void { }
Strict Mode
TypeScript strict: true is enforced. All client-side code must be TypeScript (no .js files in src/).
Type Definitions
Interfaces vs Types
// Interface for object shapes
interface GalleryImage {
readonly id: number;
url: string;
alt: string;
}
// Interface for options
interface CarouselOptions {
readonly visibleCount: number;
autoplay?: boolean;
}
// Type for unions
type GalleryLayout = 'grid' | 'masonry' | 'carousel';
// Type for function signatures
type ImageClickHandler = (image: GalleryImage, index: number) => void;
Readonly Properties
interface BlockConfig {
readonly id: string;
readonly type: string;
options: BlockOptions; // Can be modified
}
class Gallery {
private readonly element: HTMLElement;
private readonly images: readonly GalleryImage[];
}
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Classes | PascalCase | GalleryCarousel |
| Interfaces | PascalCase | CarouselOptions |
| Functions | camelCase | initCarousel() |
| Variables | camelCase | currentIndex |
| Constants | SCREAMING_SNAKE | DEFAULT_DURATION |
| Private fields | # prefix |
#currentIndex |
| Files | kebab-case | gallery-carousel.ts |
Classes
export class GalleryCarousel {
readonly #element: HTMLElement;
readonly #options: Required<CarouselOptions>;
#currentIndex = 0;
constructor(element: HTMLElement, options: CarouselOptions = {}) {
this.#element = element;
this.#options = this.#mergeOptions(options);
this.#init();
}
public goToSlide(index: number): void {
this.#currentIndex = this.#normalizeIndex(index);
this.#updateSlides();
}
public getCurrentIndex(): number {
return this.#currentIndex;
}
public destroy(): void {
this.#removeEventListeners();
}
#init(): void { }
#mergeOptions(options: CarouselOptions): Required<CarouselOptions> { }
#normalizeIndex(index: number): number { }
}
See GalleryCarousel-example.ts for the full implementation.
Functions
export function debounce<T extends (...args: unknown[]) => unknown>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout> | null = null;
return function (this: unknown, ...args: Parameters<T>): void {
if (timeoutId !== null) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
timeoutId = null;
}, wait);
};
}
See utility-functions.ts for debounce and throttle implementations.
DOM Manipulation
Type-Safe Queries
function getElement<T extends HTMLElement>(
selector: string,
parent: ParentNode = document
): T | null {
return parent.querySelector<T>(selector);
}
// Usage
const gallery = getElement<HTMLDivElement>('.gallery');
const buttons = getElements<HTMLButtonElement>('[data-action]');
Null Handling
// Early return
const element = document.querySelector<HTMLElement>('.gallery');
if (!element) return;
// Optional chaining
const width = element?.offsetWidth ?? 0;
// Assertion (use sparingly)
const button = document.querySelector<HTMLButtonElement>('.btn')!;
Event Handling
Arrow Function Methods
class Component {
#handleClick = (event: MouseEvent): void => {
event.preventDefault();
this.#doSomething();
};
#bindEvents(): void {
this.addEventListener('click', this.#handleClick);
}
#unbindEvents(): void {
this.removeEventListener('click', this.#handleClick);
}
}
Custom Events
this.dispatchEvent(
new CustomEvent('gallery:slide-change', {
bubbles: true,
detail: { index: this.#currentIndex, total: this.#slideCount },
})
);
Exports
Named Exports Only
// ✅ Good - named exports
export class GalleryCarousel { }
export function initGallery(): void { }
export type { CarouselOptions, GalleryImage };
// ❌ Bad - default exports
export default class GalleryCarousel { }
Anti-Patterns
| Avoid | Use Instead |
|---|---|
any |
Proper types or generics |
var |
const (preferred) or let |
Non-null assertion (!) without reason |
Null handling with guards |
| Implicit return types | Explicit return types |
ESLint Validation
This project uses ESLint with TypeScript-specific rules. Key rules to follow:
No Unused Variables
ESLint disallows unused variables, parameters, and imports:
/* ❌ Bad - unused parameter causes eslint error */
function updateDisplay(element: HTMLElement, value: number, isFinal: boolean): void {
element.textContent = value.toString();
// isFinal is never used!
}
/* ✅ Good - remove unused parameters */
function updateDisplay(element: HTMLElement, value: number): void {
element.textContent = value.toString();
}
/* ✅ Good - prefix with underscore if intentionally unused */
function callback(_event: Event, data: string): void {
console.log(data);
}
Key Principles
- Remove unused variables, parameters, and imports
- Prefix intentionally unused parameters with
_(underscore) - Follow all rules defined in the project's ESLint configuration
Validation
Always run ESLint after making TypeScript/JavaScript changes:
pnpm run lint:js
Fix any issues before committing. This ensures consistent code style and catches common errors.
Related Skills
- web-components - Web Component patterns
- vitest-testing - TypeScript unit testing
- block-editor-components - React editor components
- html-standards - HTML and accessibility
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?