typescript-conventions-skills
CLAUDE.md0 starsChanged 6 months agoMITView on GitHub
TypeScript conventions. Apply to every .ts, .tsx, and tsconfig*.json. Project-specific overrides win — these are defaults. Tradeoff: bias toward strict-but-modern. For one-off scripts or legacy projects with much existing JS, use judgment. Standard tsconfig.json: The extras beyond strict: true: License: MIT.
In this repository2 other files it gives its agents.
- .cursor/rules/typescript-conventions.mdcCursor rule
- typescript-conventionsSkill
The file
We split this CLAUDE.md into the rules it gives an agent
6 rules. About 0 are common, 0 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 9
strict: truealways: If a project's tsconfig doesn't have it, enabling it is the right opening move. - Very specific: line 10
Never
any: If you genuinely don't know the shape, use unknown and narrow. - Very specific: line 17
Prefer as const over enum for string-literal sets — better tree-shaking, no runtime cost
- Very specific: line 18
Prefer satisfies over type assertion (as) for object literals — preserves narrowing while validating shape
- Very specific: line 25
Always handle the rejection path — never await fn() without a try/catch or a result-type wrapper at API boundaries
- Very specific: line 27
Never Promise.race without a timeout — accidental dropped work
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
TypeScript conventions. Apply to every .ts, .tsx, and tsconfig*.json. Project-specific overrides win — these are defaults.
Tradeoff: bias toward strict-but-modern. For one-off scripts or legacy projects with much existing JS, use judgment.
Type discipline
strict: truealways. If a project's tsconfig doesn't have it, enabling it is the right opening move.- Never
any. If you genuinely don't know the shape, useunknownand narrow. - Discriminated unions over optional fields for state machines.
{ status: 'idle' } | { status: 'loading' } | { status: 'error', message: string }beats{ status: string, message?: string }. - Type-only imports (
import type { Foo } from '...') for types — keeps bundler/runtime trees clean. - Result types over throw for failure modes the caller is expected to handle. Reserve
throwfor programmer errors and unrecoverables.
Patterns
- Prefer
as constoverenumfor string-literal sets — better tree-shaking, no runtime cost - Prefer
satisfiesover type assertion (as) for object literals — preserves narrowing while validating shape readonlyon arrays and props that shouldn't mutate — catches a class of bugs at zero cost- Brand types for IDs (
type UserId = string & { readonly __brand: unique symbol }) when mixing IDs is a real risk
Async
async/awaitover raw.then()chains- Always handle the rejection path — never
await fn()without a try/catch or a result-type wrapper at API boundaries Promise.allfor parallel;Promise.allSettledwhen partial success is meaningful- Never
Promise.racewithout a timeout — accidental dropped work
Anti-patterns
any(useunknown+ narrow)// @ts-ignore(use// @ts-expect-errorso it errors when the issue is fixed)- Unsafe type assertions (
x as Foo) wheresatisfiesor a guard would work - Mutating function parameters
enum(use union literals +as const)- Catching errors and swallowing them silently (
} catch {})
Project setup
Standard tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true
}
}The extras beyond strict: true:
noUncheckedIndexedAccess—arr[0]isT | undefined, notT. Catches off-by-one + missing-key bugs.noImplicitOverride— must writeoverrideexplicitly. Catches accidental override of unrelated methods.exactOptionalPropertyTypes—{ x?: string }does NOT accept{ x: undefined }. Distinguishes "not provided" from "provided as undefined".
Tooling
tsc --noEmitas the type-check pass in CIeslintwith@typescript-eslintfor lintingprettierfor formatting (or eslint's formatting rules if you prefer one tool)vitestorjestfor tests; vitest is faster + ESM-nativetsxfor running TypeScript directly without a build step
License: MIT.
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.

