@sarj/tsconfig
v0.1.1
Published
Ultra-strict TypeScript configs for sarj-ai projects — strict.json + base.json
Maintainers
Readme
@sarj/tsconfig
Hyper-modern, maximally-strict TypeScript configs for sarj-ai projects.
Covers every type-safety flag in bulbul's tsconfig.base.json and integration-client/tsconfig.json. Per-project flags (composite, noEmit, outDir, jsx, types) and bundler-specific module resolution are intentionally omitted — see What's NOT in the preset below.
Requires
- TypeScript ≥ 6.0 — the configs use
target: "ES2025",lib: ["ES2025"],isolatedDeclarations,erasableSyntaxOnly, andstrictBuiltinIteratorReturn, all of which need TS 5.5+ at minimum and ES2025 needs TS 6.
Install
npm i -D @sarj/tsconfig typescript@^6
pnpm add -D @sarj/tsconfig typescript@^6
yarn add -D @sarj/tsconfig typescript@^6
bun add -d @sarj/tsconfig typescript@^6Use
tsconfig.json — the default for new projects:
{
"extends": "@sarj/tsconfig/strict.json",
"include": ["src/**/*"]
}For libraries that need to be less strict (e.g. mid-migration), extend the base:
{
"extends": "@sarj/tsconfig/base.json"
}What's enabled
base.json — modern defaults + bulbul-parity strict-safety
Module / target (TS 6 + Node 24 LTS):
target: "ES2025"/lib: ["ES2025"]— Iterator helpers,Promise.try, Set methods,RegExp.escape, Float16Arraymodule: "NodeNext"/moduleResolution: "NodeNext"— Node 24 native ESM resolution. Override to"preserve"/"bundler"for Next.js / Vite / Vitest / esbuild consumers (see rejection table)moduleDetection: "force"— every file is a module; no accidental global scriptsverbatimModuleSyntax: true—import typerequired for type-only importsisolatedModules: true— every file is a standalone compilation unitallowJs: false— TS-only; no.jsinfiltrationesModuleInterop/allowSyntheticDefaultImportsresolveJsonModule: true
Type-safety hygiene (matches bulbul base):
strict: truenoUncheckedIndexedAccess: true—arr[0]isT | undefinednoUncheckedSideEffectImports: true(TS 5.6+)exactOptionalPropertyTypes: truenoImplicitOverride: truenoImplicitReturns: truenoFallthroughCasesInSwitch: truenoPropertyAccessFromIndexSignature: true— bracket only for index signaturesnoUnusedLocals: true/noUnusedParameters: trueallowUnreachableCode: false/allowUnusedLabels: falseuseDefineForClassFields: true
Emit / publish:
declaration: true/declarationMap: true/sourceMap: truenewLine: "lf"— reproducible cross-platform outputstripInternal: true—@internal-tagged declarations don't shipforceConsistentCasingInFileNames: trueskipLibCheck: true
strict.json — extends base + the hyper-strict flags
isolatedDeclarations: true(TS 5.5+) — forces explicit return types on every exported symbol; enables parallel.d.tsemit bytsgo/swc/oxcerasableSyntaxOnly: true(TS 5.8+) — bans non-erasable syntax (enums, namespaces with values, parameter properties,import =); pairs with Node 24's--experimental-strip-typesnoErrorTruncation: true— full type names in errors, no...strictBuiltinIteratorReturn: true(TS 5.6+) — plugs theanyleak in built-in iterators- All strict-family sub-flags explicitly listed (
alwaysStrict,noImplicitAny,noImplicitThis,strictBindCallApply,strictFunctionTypes,strictNullChecks,strictPropertyInitialization,useUnknownInCatchVariables) — redundant withstrict: truefrom base but pinned so future TS default flips can't loosen them
What's NOT in the preset (and why)
These were considered and explicitly rejected — they're per-project decisions, not shared-config concerns:
| Flag | Why not in @sarj/tsconfig | What to set in your own tsconfig |
|------|---------------------------|----------------------------------|
| composite / incremental | Per-project; depends on whether you use project references | Add to your tsconfig if you use tsc -b |
| noEmit | App-vs-lib; apps want true, libs want false | true for Next.js / Vite apps; omit for libs |
| outDir / rootDir / paths | Per-project layout | Set per package |
| jsx | Framework-specific | "preserve" for Next.js; "react-jsx" for plain React |
| DOM / DOM.Iterable / DOM.AsyncIterable in lib | Base is Node-safe; browser packages add DOM in their own tsconfig. lib is a REPLACE field, not merge — you must include ES2025 too. | "lib": ["ES2025", "DOM", "DOM.Iterable", "DOM.AsyncIterable"] |
| types / typeRoots | Forces every consumer to enumerate ambient types — high friction | Add ["node", "vitest/globals"] etc. per project |
| Bundler module resolution | NodeNext is correct for libraries; Next.js / Vite / esbuild prefer bundler | "module": "preserve", "moduleResolution": "bundler" |
| noEmitOnError | Breaks dev/editor partial-emit workflows; gate via separate tsc --noEmit in CI | — |
| rewriteRelativeImportExtensions / allowImportingTsExtensions | Per-runtime decision (depends on whether you run .ts directly) | Set if using tsx / Bun / Deno |
Migration notes
Adopting strict.json on a brownfield codebase typically surfaces hundreds of errors. The three flags that produce the bulk:
isolatedDeclarations(TS9007) — every exported function, class, andconstneeds an explicit return type. A multi-day sweep. Runtsc --noEmit --isolatedDeclarationsfirst to see the scope.erasableSyntaxOnly— bansenum,namespace { ... value ... }, parameter properties (constructor(private x: T)),import =. Convert enums toas constliteral unions; rewrite parameter properties as explicit field assignment.exactOptionalPropertyTypes—{ x?: T }no longer accepts{ x: undefined }. Either tighten the call sites to omit the key, or widen the type to{ x?: T | undefined }.
To opt out of a single flag from your tsconfig, just set it to false (it overrides the extended preset):
{
"extends": "@sarj/tsconfig/strict.json",
"compilerOptions": {
"isolatedDeclarations": false
}
}Versioning
Semver. Major-bump on TypeScript major releases (currently TS 6.x). The package ships with sigstore provenance (npm-attested).
Influences
These configs were authored by comparing against:
- bulbul's
tsconfig.base.json(Next.js + lib monorepo baseline) andintegration-client/tsconfig.json(published SDK) @tsconfig/strictest,@total-typescript/tsconfig,sindresorhus/tsconfig,@swan-io/tsconfig,vercel/style-guide- TypeScript handbook strict-mode reference and the full TS 5.0 → 6.0 changelog
