typescript-standards
Skill0 starsChanged yesterdayMITView on GitHub
Write or review TypeScript language code, imports, compiler configuration, and type-level idioms.
10 other projects use a version of this.
Adopted by
Most recently taken up by
- gerardbalaoro/skillstheir own version, first seen Nov 1, 2026
- sapientsai/panel-mcp-servertheir own version, first seen Nov 1, 2026
- alexander-zuev/agent-skillstheir own version, first seen Oct 13, 2026
- TangleML/tangle-uitheir own version, first seen Oct 8, 2026
- BTMuli/TeyvatGuidetheir own version, first seen Oct 8, 2026
- AlemTuzlak/skillstheir own version, first seen Aug 3, 2026
Other versions10 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 10
- BTMuli/TeyvatGuide★ 434same name
- TangleML/tangle-ui★ 104same name
- AlemTuzlak/skills★ 45same name
- LiorCohen/sdd★ 43same name
- jackleekopij/claude-skills★ 3same name
- motola10/claude-code-base★ 1same name
- rkdxodud-tyk/SKILLS★ 1same name
- sapientsai/panel-mcp-server★ 1same name
- alexander-zuev/agent-skills★ 0same name
- gerardbalaoro/skills★ 0same name
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 repository34 other files it gives its agents.
- astroSkill
- bun-standardsSkill
- postgresSkill
- react-engineeringSkill
- rust-standardsSkill
- spring-bootSkill
- tailwind-v4Skill
- vitest-testingSkill
- api-designSkill
- architecture-reviewSkill
- benchmark-readiness-reviewSkill
- cli-designSkill
- codebase-scoutingSkill
- code-review-findingsSkill
- config-projection-reviewSkill
- documentation-hygieneSkill
- domain-modelingSkill
- formal-verificationSkill
- implementation-planningSkill
- orchestration-workflowSkill
- problem-clarificationSkill
- product-copySkill
- refactorSkill
- repository-text-hygieneSkill
- researchSkill
- security-scope-reviewSkill
- setup-canastaSkill
- system-designSkill
- task-closeoutSkill
- tddSkill
- technical-writingSkill
- upstream-contributionSkill
- writing-issuesSkill
- writing-prSkill
The file
We split this skill into the rules it gives an agent
12 rules. 0 are common, 7 are distinctive, and 5 are very specific to this project.
0
Common
Most of the 10 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 13
When TypeScript work adds, changes, reviews, optimizes, or migrates runtime schemas, load references/zod.md.
- Distinctive: line 18
Basis: Every rule below is derived from current official documentation, published style guides, and measured results — not from what any …
- Very specific: line 27
Use the current stable native compiler line, TypeScript 7 or later.
- Distinctive: line 32
Do not select TypeScript 6 as the primary compiler to accommodate lagging tooling.
- Very specific: line 59
Use package.json imports subpaths with a # prefix.
- Distinctive: line 78
Prefer relative imports within a bounded context and subpath imports across them.
- Distinctive: line 161
Import the context, never a package-root barrel that re-exports everything.
- Distinctive: line 162
No wildcard re-exports. No default exports.
- Distinctive: line 164
Prefer pure functions with normalized inputs at the core, and push validation, I/O, and throwing to the edge.
- Very specific: line 191
Add ESLint plus typescript-eslint only for a named, repository-relevant plugin or type-aware rule Biome cannot provide.
- Very specific: line 196
Use tsc -b project references in monorepos.
- Very specific: line 232
Verify currency before relying on this file: the compiler line, module defaults, and tooling landscape all moved during 2026.
“Common” is measured: kept by at least 6 in 10 of the 10 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
Language-level standards for every project that ships TypeScript: published
libraries, CLIs, services, and application surfaces alike. Framework choices live in
react-engineering, astro, and the upstream shadcn guidance (not bundled). Exact dependency versions belong to stack
governance, not here.
When TypeScript work adds, changes, reviews, optimizes, or migrates runtime schemas, load references/zod.md. It owns Zod selection, boundary parsing, inferred types, version compatibility, migration, and compilation; this skill continues to own the surrounding TypeScript language rules.
Basis. Every rule below is derived from current official documentation, published style guides, and measured results — not from what any repository happens to do today. Existing repos are evidence of drift, never justification for a rule. When revising this file, research first and cite the authority; where sources genuinely disagree, name the tradeoff instead of picking silently. The one section marked cross-project doctrine is the deliberate exception.
Compiler line
Use the current stable native compiler line, TypeScript 7 or later. TypeScript 7
is the Go rewrite of the same compiler, generally available since 8 July 2026,
measured 8–12x faster on full builds, shipped under the normal typescript package
and the normal tsc command.
- Do not select TypeScript 6 as the primary compiler to accommodate lagging tooling.
@typescript/typescript6may be installed side-by-side as a scoped compatibility API for a named consumer that needs the old compiler API. Record the consumer and the removal condition. It must never become the primary compiler.- Resolve exact versions from the repository manifest and lockfile, never from this file. Skills consume stack policy; they do not own versions.
Module resolution
The rule that decides everything here: who resolves this import at run time?
| Resolver | Surfaces | module | Specifiers |
| A runtime (Node/Bun) | published packages, CLIs, services | nodenext | explicit .js on relative imports |
| A bundler | Vite/Astro/Next applications | preserve | extensionless is fine |
Runtime-resolved code writes .js, even in .ts files. TypeScript does not
rewrite import specifiers on emit, so the path you write is the path Node receives.
Node's ESM resolver does not guess extensions by design. You are naming the file that
will exist after build, not the file you are editing.
module: "preserve" is the current answer for bundled code. It implies
moduleResolution: "bundler", esModuleInterop, and resolveJsonModule, and models
what bundlers actually do. Prefer it over esnext in new projects.
Aliases
Use package.json imports subpaths with a # prefix. Do not use tsconfig
paths.
{ "imports": { "#src/*": "./src/*.js" } }tsconfig paths is a type-level fiction: TypeScript resolves it for typechecking
and emits it unchanged, so it only works where a bundler or loader happens to resolve
it too. Subpath imports are resolved natively by Node, Bun, and Vite, and understood
by TypeScript since 5.4 — the same specifier works in a bundled app and a plain Node
process.
#/*alone is invalid. Use a segment:#src/*,#internal/*.- Ecosystem tooling support is thinner than blog coverage suggests. Verify that
linters, codegen, and analysis tools in the repository resolve
#before adopting it broadly. @/*is legacy. Do not introduce it into new projects.
Prefer relative imports within a bounded context and subpath imports across them.
tsconfig baseline
strict: true is the floor, not the ceiling. Enable all of these:
| Option | Why |
strict | The baseline bundle, including useUnknownInCatchVariables |
noUncheckedIndexedAccess | arr[i] and record[key] are T | undefined, which is the truth |
exactOptionalPropertyTypes | Distinguishes "absent" from "present and undefined" |
noImplicitOverride | override must be written when overriding |
noFallthroughCasesInSwitch | Catches missing break |
noPropertyAccessFromIndexSignature | Index-signature access must use brackets |
verbatimModuleSyntax | Type-only imports must say import type; emit is predictable |
moduleDetection: "force" | Every file is a module; no accidental globals |
isolatedDeclarations | Declaration emit stops depending on inference, so it parallelizes |
isolatedDeclarations is on by default for new projects and is the strongest lever
available for any package that emits declarations. It makes .d.ts generation
independent of type inference, so packages emit in parallel and external tools can
emit without invoking tsc at all; reported build improvements run 3x–15x on
monorepos. The cost is explicit types at export boundaries, which is mechanical work
an editor can generate and which improves the published API surface anyway. Enable it
from day one on new packages. Retrofitting an existing package is a bounded task, not
a rewrite.
erasableSyntaxOnly is required for any package a runtime may execute directly via
type stripping, and is good discipline everywhere else. It rejects syntax that emits
runtime code: enum, namespace with a runtime body, parameter properties, and
import = / export =.
Type-level idiom
Do not use enum. It emits a runtime object, has surprising bidirectional
mapping for numeric variants, and is banned by erasableSyntaxOnly. Use a string
literal union, or a const object when the values are needed at run time:
export type Effect = "inspect" | "modify_source" | "external_write";
export const EFFECTS = [
"inspect",
"modify_source",
"external_write",
] as const satisfies readonly Effect[];as const satisfies T is the load-bearing pattern: as const keeps the literal
types, satisfies checks conformance without widening. Reach for satisfies wherever
you would otherwise annotate and lose specificity.
- Discriminated unions over optional-field bags. Give every variant a literal
kindand let exhaustiveness checking do the work. Model impossible states out of existence rather than validating them later. readonlyby default on interface fields, arrays, and parameters. Mutability is the exception and should be visible.- Branded types for identifiers that can be mixed up. Brand an ID when code
handles two or more kinds of ID of the same base type, so a
UserIdcan't be passed where anOrderIdbelongs. In a public API, brands cost every caller a constructor call, so add them there only when callers really mix IDs. - Optional fields include
| undefined(timeoutMs?: number | undefined) underexactOptionalPropertyTypes, so a caller can forward a value that may beundefinedwithout spreading conditionally. unknown, neverany. Narrow at the boundary with a type guard or a schema parser.anydisables checking silently and spreads.- Parse, don't validate. Untrusted input crosses the boundary once, into a typed value; downstream code receives the type, not the raw shape. Follow references/zod.md when Zod owns that parser.
- Infer return types; annotate parameters and public API surfaces. Explicit return
types on exported functions are worth the redundancy, and
isolatedDeclarationsrequires them.
Project structure (cross-project doctrine)
These are the operator's architectural choices rather than externally-derived language rules. They are binding here, but do not present them as general TypeScript practice.
- One logical concern per module. Name the module by its concern; a split is not complete until the residual is also named.
- The module that owns a concern owns its vocabulary. Types live with the logic that decides over them, not in a shared type dump.
- Bounded contexts communicate through explicit interfaces and their own barrels. Import the context, never a package-root barrel that re-exports everything.
- No wildcard re-exports. No default exports; named exports only, so renames are mechanical and imports are greppable.
- Prefer pure functions with normalized inputs at the core, and push validation, I/O, and throwing to the edge. A pure core is testable, cheap to reason about, and the only shape a deterministic verifier can consume.
Folder layout for applications, following Bulletproof React's project structure (https://github.com/alan2207/bulletproof-react/blob/master/docs/project-structure.md):
- Organize by feature:
src/features/<feature>/holds that feature's components, hooks, API calls, state and types, with only the subfolders it needs. Files that change together live together. - Shared code (
src/components,src/hooks,src/lib) is for what two or more features actually use; move it there when the second one needs it. - Imports flow one way: shared → features → app. Features do not import from each other; the app layer composes them. Enforce it with the linter's import rules where it can express them.
- In an existing repository, follow its structure. Propose a reorganization as its own change, never mixed into a feature.
Tooling
- Biome is the default formatter, linter, and import organizer for new projects: roughly 20x faster than ESLint and 25x faster than Prettier on equivalent checks, in one tool with one config. Its documented limit is rule coverage — it implements most common ESLint rules but not the long tail, and type-aware linting is thinner.
tsc --noEmitis the authoritative typecheck. Type stripping and bundlers do not check types; they delete them. A type error will not stop a stripped program at run time, sotscmust run in CI regardless of how the code executes.- Add ESLint plus
typescript-eslintonly for a named, repository-relevant plugin or type-aware rule Biome cannot provide. Do not run two overlapping checkers by default. A repository already invested in ESLint plugins should keep them rather than lose rule depth; the current pattern there is a fast pre-pass linter ahead of ESLint, not a rewrite. - Use
tsc -bproject references in monorepos; setcomposite: trueper package. - Vitest for tests. Test behavior through the public API, not internals.
@ts-expect-errorwith a reason, never@ts-ignore. The former fails when the underlying error is fixed, so it cannot rot silently.
Anti-patterns
| Do not | Instead |
enum / const enum | string literal union, or const object as const satisfies |
namespace | ES modules |
any | unknown plus narrowing |
as Foo to silence an error | type guard, satisfies, or fix the type |
Non-null ! | narrow explicitly, or make the type honest |
@ts-ignore | @ts-expect-error with a reason |
tsconfig paths aliases | package.json imports subpaths |
| Extensionless relative imports in runtime-resolved code | explicit .js |
| Default exports | named exports |
Function, Object, {} as types | a precise signature or unknown |
| Optional fields to model variants | discriminated union |
| Mutating a parameter | return a new value |
References
- TypeScript TSConfig reference — strict
flag semantics,
module: "preserve",verbatimModuleSyntax - TypeScript modules theory — why specifiers are not rewritten on emit
isolatedDeclarations— parallel declaration emit and its export-annotation requirement- Node.js TypeScript support — type
stripping, erasable syntax, and why
tscmust still run - Google TypeScript Style Guide — enum and export conventions
- ts.dev style guide — the public form of the same guidance
Verify currency before relying on this file: the compiler line, module defaults, and
tooling landscape all moved during 2026.
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.

