epicenterhq/epicenter

tsconfig

TypeScript config conventions for this monorepo: the two-base layering, the seven leaf tiers, and the never-redeclare list. Use when adding a package, editing any tsconfig.json, picking a tier for a new app, or debugging module resolution.

First seen May 30, 2026

Installation

$ npx skills add epicenterhq/epicenter --skill tsconfig

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from epicenterhq/epicenter · top by installs.

npx skills add epicenterhq/epicenter

Browse all from epicenterhq/epicenter

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 4.8K
License licenses
Default branch main
Open issues 125
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0
More metadata
author
epicenter
version
1.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,946 B
  • docs SUMMARY.md 255 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 5 installs

SKILL.md

tsconfig conventions

Every package here is source-only .ts: exports point at ./src/*.ts, there is no build step, and consumers (Bun, Vite, Tauri, the Cloudflare Worker) operate on raw .ts. That single fact decides the whole config.

The exceptions are the audience, not the package. packages/workspace and packages/field are published for toolchains we do not control, so shipping source would subject them to a stranger's compiler settings. They emit .js and .d.ts, and their exports point at ./dist. Each leaf tsconfig.json is an ordinary tier from the table below; the emit lives in a sibling tsconfig.build.json that extends the leaf and turns on exactly what emitting needs (noEmit: false, outDir, rootDir, declaration, types: []). Do not add outDir, declaration, or noEmit: false to any leaf. If another package earns a build, copy that split.

The one rule

A leaf tsconfig.json may set only: types, library-only strictness (noUnusedLocals/noUnusedParameters), checkJs (SvelteKit), and genuinely package-specific options (jsx, paths, customConditions, include).

Anything else belongs in a base. If a leaf option repeats a base value or a TypeScript default, delete it.

Two base files

tsconfig.base.json   universal: target/lib[ESNext], module preserve, strict,
                     noEmit, isolatedModules, verbatimModuleSyntax, types []
tsconfig.dom.json    extends base; its ONLY job is lib [ESNext, DOM, DOM.Iterable]

There is no tsconfig.base.lib.json and no project references. Source-only packages never emit, so composite/declaration/outDir have no place in a leaf. The two published packages that do emit put them in their own tsconfig.build.json (see above), never in the leaf or a base.

Module strategy: one, repo-wide

module: "preserve" + moduleResolution: "bundler". preserve implies bundler (TS 5.4+); the explicit pair is kept for legibility. Never use NodeNext anywhere: nothing in this repo is published as emitted Node ESM, and bundler resolution already reads package.json imports/exports.

The seven leaf tiers

Pick the tier, copy the shape, change nothing else.

Tier extends Leaf adds
Bun library "../../tsconfig.base.json" types:["bun"], noUnusedLocals, noUnusedParameters
Node library "../../tsconfig.base.json" types:["node"], noUnusedLocals, noUnusedParameters
Svelte library "../../tsconfig.dom.json" types:["bun"], noUnusedLocals, noUnusedParameters
SvelteKit app ["../../tsconfig.base.json", "./.svelte-kit/tsconfig.json"] checkJs:true, types:["bun"]
Cloudflare Worker "../../tsconfig.base.json" jsx, jsxImportSource, types, include
Bun app "../../tsconfig.base.json" types:["bun"], include
Astro app ["../../tsconfig.base.json", "astro/tsconfigs/strict"] astro include/exclude

A generated config (./.svelte-kit/tsconfig.json) goes last in the array so its lib/module win where they must. Never hand-edit a generated config.

The two canonical library shapes in full:

// bun library: packages/data, workspace, field, sqlite, sync, identity, ...
{
	"extends": "../../tsconfig.base.json",
	"compilerOptions": {
		"types": ["bun"],
		"noUnusedLocals": true,
		"noUnusedParameters": true
	}
}

// svelte library: packages/ui, packages/svelte
{
	"extends": "../../tsconfig.dom.json",
	"compilerOptions": {
		"types": ["bun"],
		"noUnusedLocals": true,
		"noUnusedParameters": true
	}
}

Never redeclare these (base value or TS default)

Putting any of these in a leaf is dead weight. Delete on sight.

Do not write in a leaf Why
module: "preserve" already in tsconfig.base.json
moduleResolution, target, noEmit, strict, isolatedModules already in the base
lib: ["ESNext"] the base default; use tsconfig.dom.json if you need DOM
noPropertyAccessFromIndexSignature: false that is already the TS default
useDefineForClassFields: true default when target >= ES2022
forceConsistentCasingInFileNames default true since TS 5.0
resolvePackageJsonExports default true under moduleResolution: bundler
sourceMap no-op under noEmit
single-element extends array use the string form: "extends": "../../tsconfig.base.json"

types is opt-in, on purpose

The base sets types: [] to disable auto-inclusion of every node_modules/@types package. Each leaf opts in: ["bun"] for almost everything, ["node"] for the one package that uses @types/node. Do not hoist ["bun"] to a base: a package without @types/bun installed would then fail with Cannot find type definition.

include rules

  • TypeScript does not merge include across extends. A leaf include

fully replaces the inherited one. For SvelteKit apps this means: do not set your own include, or you drop the generated ambient.d.ts/$types globs.

  • Only set include when you must narrow scope for a real reason; comment why.

Adding a new package

  1. Scaffold via the monorepo skill's boilerplate.
  2. Pick a tier from the table above; copy that exact shape.
  3. package.json uses exports only, no main/types. Entry point is

./src/index.ts.

  1. bun install at the repo root, then bun typecheck.

Background

The full rationale, the migration that established this layout, and the baseline typecheck state are in specs/20260522T190000-modernize-monorepo-tsconfig.md.