with one click
typescript
Must use any time a TypeScript file is read or written.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Must use any time a TypeScript file is read or written.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Use agent-browser for browser automation against real rendered web pages or web apps. Trigger when tasks require navigation, element interaction, extracting rendered data, or taking screenshots. Do not use for static fetches, direct API calls, or non-browser work.
Use when the user wants to scrape websites, crawl or map URLs, search the web, extract structured data from web pages, or run AI web agents using the Firecrawl API from the command line.
Create, revise, and validate effective skills. Use when adding a new skill or changing an existing skill's SKILL.md, bundled scripts, references, assets, scaffold templates, or validation tooling.
Must use whenever Bun is used.
OpenCode session storage locations and inspection guidance. Use when asked where OpenCode stores session data, chat history, local databases, or repo-specific session metadata.
Apply Go coding rules, design principles, and project conventions for maintainable Go code and repositories. Use when writing, reviewing, refactoring, or releasing Go code, or when working on Go-specific project structure, APIs, tests, CI, or binaries. Do not use for non-Go codebases or for language-agnostic tasks that do not depend on Go conventions.
| name | typescript |
| description | Must use any time a TypeScript file is read or written. |
| author | alexgorbatchev |
Guidelines, conventions, and requirements for writing high-quality, type-safe, and maintainable TypeScript code.
any typeas Type (exceptions: branded types, DOM elements, test mocks)as anyrequire() statementsimport("vite").PluginOptionawait import()) outside lazy-loading, optional dependency, or plugin boundariesimport * as Foo or export * as Fooimport { Foo as Bar }) when there is no name conflict or clarity benefitFilename must match the exact name and casing of the primary exported element:
createUser → createUser.tsUserProfile → UserProfile.tsIUserService → IUserService.tsConfig → Config.tsEach file should have a single primary export. If multiple related items are exported, name the file after the most important one.
Special cases:
constants.tsstringUtils.ts, dateUtils.tstypes.ts (must not contain implementations)index.ts (re-exports public API only){sourceFileName}.test.ts in __tests__/Also follow these ownership-location rules:
.tsx files live under components/, templates/, or layouts/, using ComponentName.tsx by default or component-name.tsx when the shared config uses FilenameStyle.DashCaseuse live in direct-child hooks/useThing.ts[x] files by default or hooks/use-thing.ts[x] when the shared config uses FilenameStyle.DashCasestories/ directories are reserved for *.stories.tsx, helpers.ts[x], fixtures.ts[x], and fixtures/__tests__/ directories are reserved for *.test.ts[x], helpers.ts[x], fixtures.ts[x], and fixtures/| Pattern | Use For |
|---|---|
camelCase | Variables, functions, methods, properties |
PascalCase | Classes, interfaces, types, enums |
SCREAMING_SNAKE_CASE | Constants |
IInterface | Interface names |
kebab-case | CSS classes |
Prefix with: is, has, can, should, will, does
// ✅
const isValid = true;
const hasPermission = false;
// ❌
const valid = true;
Always use error, never err or e:
// ✅
catch (error) { }
// ❌
catch (err) { }
Be consistent within context:
// ✅ Consistent
const sourcePath = '/src';
const destinationPath = '/dest';
// ❌ Mixed
const sourcePath = '/src';
const dest = '/dest';
Avoid unnecessary single-use variables. Keep intermediate variables when they improve clarity, debugging, or narrowing:
// ✅ Direct usage is clear
console.log(determinePath());
// ✅ Intermediate variable adds intent/context
const resolvedPath = determinePath();
logger.debug({ resolvedPath });
// ❌ Avoid needless pass-through names
const finalPath = determinePath();
console.log(finalPath);
// ✅
const item = array[0];
if (item) {
// use item
}
// ❌
array[0] as string;
// ✅
const value: ExpectedType = sourceValue;
// ❌
const value = sourceValue as ExpectedType;
Exported/public functions must declare explicit return types. Local callbacks and obvious local helpers may rely on inference:
// ✅ Public API has explicit return type
export function createUser(name: string): UserResult {
return { id: generateId(), name, createdAt: new Date() };
}
// ✅ Local callback can rely on inference
const names = users.map((user) => user.name);
// ❌ Public function without explicit return type
export function createUser(name: string) {
return { id: generateId(), name, createdAt: new Date() };
}
Variables not from function calls need explicit types. Prefer existing named types or inference; avoid inline type definitions:
// ✅
type Metadata = { tarballUrl: string; };
type OperationResult = { success: boolean; metadata: Metadata; };
function getResults(): Promise<OperationResult>;
// ✅
import type { PluginOption } from 'vite';
const plugin: PluginOption = {};
// ❌
function getResults(): Promise<{ success: boolean; metadata: { tarballUrl: string; }; }>;
// ❌
const plugin: import('vite').PluginOption = {};
Use type guard functions for complex/custom types. Built-in type checks (typeof for primitives, Array.isArray) are fine:
// ✅ Type guard for custom types
function isUserProfile(value: unknown): value is UserProfile {
return typeof value === 'object' && value !== null && 'id' in value && 'name' in value;
}
if (isUserProfile(data)) {
// data is typed as UserProfile
}
// ✅ Built-in checks for primitives are fine
if (typeof input === 'string') {}
if (typeof count === 'number') {}
if (Array.isArray(items)) {}
Re-export public API through index.ts files at package/module boundaries. Internal/private folders do not need barrel files unless they improve discoverability.
src/
├── index.ts // Public API re-exports only
├── UserService.ts
├── validation/
│ ├── index.ts // Public validation API
│ └── emailValidator.ts
└── internal/
└── formatLog.ts // No index.ts required (private implementation)
Prefer explicit exports in boundary index.ts files for stable public APIs. Wildcard exports are acceptable for small internal modules with low collision risk.
// ✅ package boundary index.ts
export { createUser } from './createUser';
export { UserService } from './UserService';
export { validateEmail } from './validation';
// ⚠️ acceptable in small internal modules
export * from './validation';
// ❌ avoid broad wildcard exports in package public API
export * from './createUser';
export * from './UserService';
index.ts as a pure barrel instead of mixing in local runtime logic.constants.ts value-only.types.ts type-only.constants.ts.types.ts.Core logic should be implemented as pure functions where possible. A pure function's output must depend only on its explicit input arguments, and it must not cause side effects (e.g., modifying external state, performing I/O).
Operations with side effects (e.g., file system access, network requests, direct logging to console/files, reading system env or properties) must be isolated from pure core logic. These side effects should be handled at the "edges" of the application (e.g., in the main entry point, dedicated I/O modules, or specific command handlers).
Functions that orchestrate operations but need to invoke side effects must receive the necessary handlers (e.g., FileSystem instance, HTTP client, logger instance) as arguments. No singletons - pass dependencies explicitly. Design for testability - all dependencies should be injectable.
Configuration objects derived from external sources (like environment variables) must be created by pure functions. These functions receive all necessary raw inputs (e.g., an object representing environment variables, system properties) as arguments and should use appropriate validation libraries to parse and transform these inputs into a typed configuration object. This validated configuration object is then created at the application's main entry point and passed down via dependency injection.
tsc as the default compiler and typechecker.@foo/bar packagesFor testing guidelines, patterns, and organization (including conditional logic restrictions, exact string matching, snapshots, and fixtures), see testing.md.
When working on React components or tests:
act(...) warning failure scheduling, and component logic test patterns, see react-testing.md.When creating, updating, or reviewing Storybook stories or writing play browser interaction tests: