typescript
Skill1 starsChanged 7 months agoMITView on GitHub
TypeScript coding standards and type safety conventions. Use when: creating TypeScript files, defining interfaces and types, writing type-safe code, reviewing TypeScript for type correctness, auditing a codebase for type safety gaps, eliminating any or ts-ignore usage, or improving strict-mode compliance. Covers strict typing, avoiding any and ts-ignore, discriminated unions, Zod runtime validation, immutability patterns, and proper type definitions.
66 other projects use a version of this.
Adopted by
Most recently taken up by
- bbartling/open-fddtheir own version, first seen Nov 9, 2026
- TheLunchTrae/claude-code-configstheir own version, first seen Nov 8, 2026
- testdino-hq/google-styleguides-skillstheir own version, first seen Nov 8, 2026
- lobehub/lobehubtheir own version, first seen Nov 5, 2026
- its-ash/skillstheir own version, first seen Nov 1, 2026
- sentimony/skillstheir own version, first seen Nov 1, 2026
Used with
Projects with it also use msw, rust and 9 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
thongdn-itSkillmsw
MSW (Mock Service Worker) best practices for API mocking in tests (formerly test-msw). This skill should be used when setting up MSW, writing request handlers, or mocking HTTP APIs. This skill does NOT cover general testing patterns (use test-vitest or test-tdd skills) or test methodology.
Also in 3 projects that use this
MicrosoftSkillrust
Use this guide when working on Rust changes in the FAST monorepo.
Also in 9 projects that use this
SupabaseSkillreact-hook-form
Correct React Hook Form usage anywhere in the monorepo — data flow, subscriptions,
Also in 3 projects that use this
VercelSkillreact
React renderer for json-render that turns JSON specs into React components. Use when working with @json-render/react, building React UIs from JSON, creating component catalogs, or rendering AI-generated specs.
Also in 10 projects that use this
leonaaardobSkilldrizzle
Complete Drizzle ORM documentation in markdown format. Use when working with Drizzle ORM - covers schema definition, queries, migrations, database connections (PostgreSQL, MySQL, SQLite), integrations (Neon, Supabase, PlanetScale, Cloudflare D1, Turso), column types, relations, transactions, and framework usage (Next.js, SvelteKit, Astro).
Also in 3 projects that use this
thongdn-itSkilltailwind
Tailwind CSS v4 performance optimization and best practices guidelines (formerly tailwindcss-v4-style). This skill should be used when writing, reviewing, or refactoring Tailwind CSS v4 code to ensure optimal build performance, minimal CSS output, and correct usage of v4 features. Triggers on tasks involving Tailwind configuration, @theme directive, utility classes, responsive design, dark mode, container queries, or CSS generation optimization.
Also in 5 projects that use this
- +1 more from thongdn-it
Other versions66 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 66
- lobehub/lobe-chat★ 84ksame name
- lobehub/lobehub★ 84ksame name
- recharts/recharts★ 28ksame name
- ccusage/ccusage★ 19ksame name
- ryoppippi/ccusage★ 19ksame name
- scalar/scalar★ 16ksame name
- prowler-cloud/prowler★ 15ksame name
- microsoft/fast★ 9.7ksame name
- epicenter-md/epicenter★ 4.8ksame name
- EpicenterHQ/epicenter★ 4.8ksame name
56 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository42 other files it gives its agents.
- accessibility-testingSkill
- alternatives-analysisSkill
- anomaly-detectionSkill
- api-designSkill
- async-messagingSkill
- caching-strategiesSkill
- chartsSkill
- cicdSkill
- code-reviewSkill
- commsSkill
- critical-feedbackSkill
- data-analysisSkill
- databaseSkill
- data-migrationsSkill
- data-visualizationSkill
- dependency-managementSkill
- dockerSkill
- error-handlingSkill
- feature-flagsSkill
- git-workflowSkill
- goalsSkill
- ide-setupSkill
- large-changeSkill
- logging-metricsSkill
- markdown-docsSkill
- mcp-serverSkill
- meeting-agendasSkill
- okrsSkill
- presentationsSkill
- product-managementSkill
- prompt-writingSkill
- pythonSkill
- reclassificationSkill
- release-managementSkill
- retrospectivesSkill
- roadmap-planningSkill
- securitySkill
- stakeholder-commsSkill
- statisticsSkill
- status-updatesSkill
- testingSkill
- ticket-writingSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. 0 are common, 4 are distinctive, and 13 are very specific to this project.
0
Common
Most of the 52 edited versions we read keep these.
4
Distinctive
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 18
Create valid, well-defined types for all data structures.
- Very specific: line 20
Never use
anytype: - use unknown if the type is truly unknown, then narrow with type guards. - Very specific: line 21
Prefer interface for object shapes that may be extended.
- Very specific: line 48
Use discriminated unions for any type that can be one of several variants.
- Distinctive: line 94
Every variant must include the discriminator field.
- Very specific: line 95
Use switch with exhaustive checks — add a default: never assertion to catch unhandled variants:
- Distinctive: line 114
Use Zod to validate data at system boundaries — API responses, config files, user input, environment variables.
- Very specific: line 206
Use readonly on interface properties that should not be mutated after creation.
- Very specific: line 207
Use ReadonlyArray<T> or readonly T[] for arrays that should not be modified.
- Very specific: line 208
Use Readonly<T> for shallow immutability, DeepImmutable<T> for state shared across boundaries.
- Very specific: line 209
Update immutable state with spread: { ...prev, field: newValue }, never with assignment.
- Very specific: line 240
Check signal.aborted before expensive operations in long-running loops.
- Very specific: line 246
Prefer readonly for properties that should not be mutated.
- Very specific: line 247
Use as const for literal type inference on constants.
- Very specific: line 249
Use satisfies operator to validate types while preserving inference:
- Very specific: line 284
Use barrel exports (index.ts) sparingly and only at module boundaries.
- Distinctive: line 285
Prefer named exports over default exports for better refactoring support.
“Common” is measured: kept by at least 6 in 10 of the 52 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
TypeScript Standards
When to Use
- Creating or modifying TypeScript files
- Defining types, interfaces, or type utilities
- Reviewing TypeScript code for type safety
Type Safety
- Create valid, well-defined types for all data structures.
- Never use
@ts-ignore- fix the underlying type issue instead. - Never use
anytype - useunknownif the type is truly unknown, then narrow with type guards. - Prefer
interfacefor object shapes that may be extended; usetypefor unions, intersections, and computed types.
Type Definitions
// Prefer interfaces for object shapes
interface User {
id: string;
name: string;
email: string;
role: UserRole;
}
// Use type for unions and computed types
type UserRole = "admin" | "editor" | "viewer";
type UserMap = Record<string, User>;
// Use generics for reusable patterns
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}Discriminated Unions
Use discriminated unions for any type that can be one of several variants. Add a literal type field as the discriminator:
// Define variants with a shared discriminator field
interface LoadingState {
type: "loading";
}
interface SuccessState<T> {
type: "success";
data: T;
}
interface ErrorState {
type: "error";
error: string;
retryable: boolean;
}
type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState;
// TypeScript narrows automatically in switch/if blocks
function render(state: AsyncState<User[]>) {
switch (state.type) {
case "loading":
return <Spinner />;
case "success":
return <UserList users={state.data} />; // data is typed as User[]
case "error":
return <ErrorMessage message={state.error} />;
}
}When to Use Discriminated Unions
| Use case | Example |
| State machines | idle → loading → success | error |
| Command/event types | { type: "create" } | { type: "update" } | { type: "delete" } |
| API responses | Different shapes per endpoint or error type |
| Configuration variants | { transport: "stdio" } | { transport: "http", url: string } |
Rules
- The discriminator field must be a string literal type, not a broad
string. - Every variant must include the discriminator field.
- Use
switchwith exhaustive checks — add adefault: neverassertion to catch unhandled variants:
function assertNever(x: never): never {
throw new Error(`Unexpected variant: ${JSON.stringify(x)}`);
}
function handleCommand(cmd: Command) {
switch (cmd.type) {
case "create": return handleCreate(cmd);
case "update": return handleUpdate(cmd);
case "delete": return handleDelete(cmd);
default: return assertNever(cmd); // compile error if a variant is missing
}
}Runtime Validation with Zod
Use Zod to validate data at system boundaries — API responses, config files, user input, environment variables. Zod bridges the gap between TypeScript's compile-time types and runtime reality.
import { z } from "zod";
// Define schema — this is the single source of truth
const UserSchema = z.object({
id: z.string(),
name: z.string().min(1).max(100),
email: z.string().email(),
role: z.enum(["admin", "editor", "viewer"]),
});
// Derive the TypeScript type from the schema
type User = z.infer<typeof UserSchema>;
// Validate at runtime
function parseUser(data: unknown): User {
return UserSchema.parse(data); // throws ZodError on invalid input
}
// Safe parse (returns result instead of throwing)
const result = UserSchema.safeParse(data);
if (result.success) {
console.warn(result.data.name); // typed as User
} else {
console.error(result.error.issues);
}When to Use Zod
| Boundary | Example |
| External API responses | Parse JSON before trusting it |
| Configuration files | Validate settings, frontmatter, manifests |
| Environment variables | Validate and type env vars at startup |
| User input | Form data, URL params, CLI arguments |
| Webhook payloads | Verify structure before processing |
Zod Patterns
// Discriminated union schemas
const EventSchema = z.discriminatedUnion("type", [
z.object({ type: z.literal("click"), x: z.number(), y: z.number() }),
z.object({ type: z.literal("keypress"), key: z.string() }),
]);
// Coercion for env vars (strings → typed values)
const EnvSchema = z.object({
PORT: z.coerce.number().default(3000),
DEBUG: z.coerce.boolean().default(false),
DATABASE_URL: z.string().url(),
});
// Reusable schema composition
const PaginationSchema = z.object({
limit: z.number().int().min(1).max(100).default(25),
cursor: z.string().optional(),
});Rules
- Schema is the source of truth — derive TypeScript types with
z.infer<>, don't duplicate. - Validate at boundaries, trust internally — once data passes Zod, pass the typed result through your code without re-validating.
- Use
safeParsefor user-facing errors — returns structured error details. Useparsefor internal assertions where failure is a bug.
Immutability Patterns
Enforce immutability at the type level to prevent accidental mutations in shared state:
// Deep immutable wrapper — prevents mutations at any depth
type DeepImmutable<T> = T extends Map<infer K, infer V>
? ReadonlyMap<DeepImmutable<K>, DeepImmutable<V>>
: T extends Set<infer S>
? ReadonlySet<DeepImmutable<S>>
: T extends object
? { readonly [K in keyof T]: DeepImmutable<T[K]> }
: T;
// Use for state that must not be mutated
interface AppState {
readonly settings: DeepImmutable<Settings>;
readonly permissions: DeepImmutable<PermissionRules>;
}Rules
- Use
readonlyon interface properties that should not be mutated after creation. - Use
ReadonlyArray<T>orreadonly T[]for arrays that should not be modified. - Use
Readonly<T>for shallow immutability,DeepImmutable<T>for state shared across boundaries. - Update immutable state with spread:
{ ...prev, field: newValue }, never with assignment.
Abort Signal / Cancellation
Propagate AbortSignal through async operations for proper cancellation:
async function fetchData(url: string, signal: AbortSignal): Promise<Data> {
const response = await fetch(url, { signal });
return response.json() as Promise<Data>;
}
// Type guard for abort errors (multiple sources)
function isAbortError(error: unknown): boolean {
return (
error instanceof DOMException && error.name === "AbortError" ||
error instanceof Error && error.name === "AbortError"
);
}
// Usage with cleanup
const controller = new AbortController();
try {
const data = await fetchData("/api/users", controller.signal);
} catch (error) {
if (isAbortError(error)) return; // expected cancellation, not an error
throw error;
}- Pass
AbortSignalto all async functions that support cancellation. - Check
signal.abortedbefore expensive operations in long-running loops. - Distinguish abort errors from real failures — don't log aborts as errors.
Best Practices
- Enable
strictmode intsconfig.json. - Prefer
readonlyfor properties that should not be mutated. - Use
as constfor literal type inference on constants. - Leverage type narrowing with
typeof,instanceof, and custom type guards over type assertions. - Use
satisfiesoperator to validate types while preserving inference:
// satisfies checks the type without widening — preserves literal types
const ROUTES = {
home: "/",
about: "/about",
settings: "/settings",
} as const satisfies Record<string, string>;
// ROUTES.home is typed as "/" (literal), not stringtsconfig.json
Enable strict mode and recommended compiler options:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}Module Organization
- One primary export per file. Co-locate related types in the same file.
- Use barrel exports (
index.ts) sparingly and only at module boundaries. - Prefer named exports over default exports for better refactoring support.
For React-specific patterns with TypeScript, TailwindCSS, and Vite, see the web-ui skill. For runtime validation at API boundaries using Zod, see the api-design skill.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

