@dvashim/typescript-config
v5.0.2
Published
Shared TypeScript configurations
Readme
TypeScript Configurations
@dvashim/typescript-config provides shareable tsconfig.json presets for libraries, React applications, and Node.js tooling — strict ES2025 + ESM defaults with bundler module resolution.
Contents
Quick start
Install the package together with TypeScript:
npm install -D @dvashim/typescript-config typescriptCreate a tsconfig.json that extends a preset:
// tsconfig.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config",
"compilerOptions": { "noEmit": true },
"include": ["src"]
}Verify the setup:
npx tscA clean exit means the preset resolved and your sources type-check. Pick the right preset for your project type in Choosing a preset — some presets need a companion package, listed per preset under Usage.
Why
These presets encode an opinionated, modern-TypeScript baseline so you don't have to re-derive it per project:
- Maximum type safety — full
strictplusexactOptionalPropertyTypes,noUncheckedIndexedAccess,noUnusedLocals/noUnusedParameters, and more. - ESM-only, bundler-first — ES2025 module output with
moduleResolution: "bundler"; no downleveling or polyfilling is performed. - Erasable-only syntax — no enums, namespaces, or parameter properties, so files transpile in isolation and stay portable across
tsc, esbuild, swc, and Node's native type stripping.
The presets lean on TypeScript 7 defaults rather than restating them — see Options for the exact list — so they stay small and track upstream. They are intended for greenfield ES2025 projects that ship or consume ESM on a recent toolchain, not for CommonJS, legacy targets, or projects that need enums or namespaces.
Requirements
- TypeScript
>=7.0.0, declared as a peer dependency. - A runtime that supports ES2025 — Node.js >= 24 or a current evergreen browser; these presets do not downlevel or polyfill.
- A bundler or a TypeScript-aware runner — the presets use
moduleResolution: "bundler".
Some presets also require a companion package (@types/node, vite, React's types); each preset's Usage section lists its own.
Compatibility
| @dvashim/typescript-config | TypeScript |
| ---------------------------- | ---------- |
| >=5.0.0 (current) | >=7.0.0 |
| 2.x–4.x | >=6.0.0 |
| 1.x | 5.x |
Changes that can surface new type errors in consuming projects ship as major versions.
Installation
typescript is a peer dependency (>=7.0.0); it is not bundled and won't always be installed automatically (e.g. pnpm without auto-install-peers), so install it alongside this package.
npm:
npm install -D @dvashim/typescript-config typescriptor pnpm:
pnpm add -D @dvashim/typescript-config typescriptPresets
| Preset | Import specifier | Use when |
| ------ | ---------------- | -------- |
| Base | @dvashim/typescript-config | Composing your own preset on the strict ES2025 + ESM foundation |
| Library development | @dvashim/typescript-config/lib-dev | Developing a publishable library (declarations, composite, source maps) |
| Library production | @dvashim/typescript-config/lib-prod | Cutting release builds of a library (strips maps, comments, @internal) |
| React JSX application | @dvashim/typescript-config/app-react | Building a React app with a non-Vite bundler |
| Vite + React JSX application | @dvashim/typescript-config/app-react-vite | Building a React app with Vite |
| Node | @dvashim/typescript-config/node | Type-checking Node.js tooling and config files |
Choosing a preset
- Publishing a library? Use
"extends": "@dvashim/typescript-config/lib-dev"while developing andlib-prodfor release builds — see Library presets. - Building a React app with Vite? Use
"extends": "@dvashim/typescript-config/app-react-vite"— see Vite React preset. - Building a React app with another bundler? Use
"extends": "@dvashim/typescript-config/app-react"— see React preset. - Type-checking Node.js tooling (build scripts, config files)? Use
"extends": "@dvashim/typescript-config/node"— see Node preset. - Building a Node.js application or service? There is no dedicated preset: extend the base, add
"types": ["node"](with@types/nodeinstalled), and pick an emit strategy — anoutDiriftscbuilds it, ornoEmitplus a bundler or runner. Iftsccompiles your service, the library presets also work. - Anything else? Use
"extends": "@dvashim/typescript-config"(the base preset) and add what you need.
Usage
Every preset is consumed the same way: a tsconfig.json that extends the import specifier, plus your include paths. The snippets below are complete files.
Base preset
The strict ES2025 + ESM foundation with bundler resolution — maximum type safety, verbatim module syntax, and erasable-only syntax. All other presets extend it.
// tsconfig.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config",
"include": ["src"]
}The base preset sets neither
noEmitnoroutDir, so a plaintscrun emits.jsfiles next to your sources. Add"noEmit": truefor check-only setups, or anoutDirwith an explicitrootDirif you wanttscoutput — TypeScript 7 rejects anoutDirwhoserootDiris left implicit when sources sit in a subdirectory (TS5011).
Library presets: lib-dev and lib-prod
A library uses the two presets together. tsconfig.json extends lib-dev and drives the editor and development builds — declarations with declaration maps, source maps, .ts → .js import rewriting, and explicit type annotations on exports (isolatedDeclarations). tsconfig.prod.json extends lib-prod for release builds — it strips source maps, declaration maps, comments, and @internal declarations.
// tsconfig.json — development and editor
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config/lib-dev",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}// tsconfig.prod.json — release builds
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config/lib-prod",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}Both presets emit, so set
outDir(and usuallyrootDir) yourself; otherwise output lands next to your sources. Becausecompositeis on, compile in build mode:tsc -b(ortsc -b -w) during development andtsc -b tsconfig.prod.jsonfor releases — this gives you incremental builds, project references (monorepos), and a.tsbuildinfocache. The two configs share anoutDirbut keep separate.tsbuildinfocaches, so clean the output directory (or pass--force) before a release build to keep stale development artifacts (.js.map,.d.ts.map) out of the published package.
React preset: app-react
For React applications bundled by a non-Vite tool. Adds the DOM libs (DOM, DOM.Iterable, DOM.AsyncIterable), the automatic JSX runtime, and .ts/.tsx extension imports; noEmit is on because the bundler produces output.
Requires React's types for the automatic JSX runtime — npm install react and npm install -D @types/react (add @types/react-dom when rendering to the DOM). Without them, every .tsx file fails with TS2875 ("This JSX tag requires the module path 'react/jsx-runtime' to exist").
// tsconfig.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config/app-react",
"include": ["src"]
}Vite React preset: app-react-vite
Extends the React preset with Vite client types (import.meta.env, import.meta.hot, asset imports).
Requires vite in the same package, in addition to the React type packages above — the vite/client types ship inside the vite package itself (there is no @types/vite). In a pnpm workspace, vite must be a dependency of the package that extends this preset, not only of the workspace root. Without it, tsc fails with TS2688: Cannot find type definition file for 'vite/client'.
// tsconfig.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config/app-react-vite",
"include": ["src"]
}Node preset
For Node.js tooling and config files (build scripts, vite.config.ts) — type-checking only, noEmit is on.
Requires @types/node: npm install -D @types/node. Without it, tsc fails with TS2688: Cannot find type definition file for 'node'.
// tsconfig.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config/node",
"include": ["vite.config.ts"]
}The preset keeps the inherited
moduleResolution: "bundler"and allows.tsextension imports, so execute these files with a bundler or a TypeScript-aware runner (Vite,tsx, esbuild, swc). The erasable-only syntax means the files transpile anywhere, but Node's native type stripping (enabled by default since Node 23.6) expectsnodenext-style resolution and explicit file extensions — for direct execution, use a runner liketsxor compile first.
Combining presets in one project
A single project often needs two presets — for example, a Vite app whose src is checked by app-react-vite while vite.config.ts is checked by node. Use a solution-style root config with project references, and run tsc -b to check both:
// tsconfig.json
{
"files": [],
"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
}// tsconfig.app.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config/app-react-vite",
"include": ["src"]
}// tsconfig.node.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@dvashim/typescript-config/node",
"include": ["vite.config.ts"]
}Composing presets
- Ambient types are off by default. TypeScript 7 defaults to
types: [], so@types/*packages are not auto-discovered. If you rely on global types (e.g.node,vite/client,vitest/globals), add them totypesin your own config — the Node and Vite presets already do this for their cases. - Layering presets.
extendsaccepts an array, so you can compose a preset with project-specific overrides, e.g."extends": ["@dvashim/typescript-config/node", "./tsconfig.paths.json"].
Options
Base
Options listed below are set explicitly. Additional options rely on TypeScript 7 defaults rather than being restated: strict, module: "esnext", moduleResolution: "bundler", noUncheckedSideEffectImports, forceConsistentCasingInFileNames, useDefineForClassFields, esModuleInterop, and types: [] (blocks ambient @types/* auto-discovery).
| Option | Value | Effect |
| ------ | ----- | ------ |
| exactOptionalPropertyTypes | true | Types optional properties strictly as T \| undefined |
| noFallthroughCasesInSwitch | true | Errors on fallthrough switch cases |
| noImplicitOverride | true | Requires the override keyword on class member overrides |
| noImplicitReturns | true | Errors when not all code paths return a value |
| noPropertyAccessFromIndexSignature | true | Disallows dot access for index-signature-only properties |
| noUncheckedIndexedAccess | true | Adds undefined to index-signature access types |
| noUnusedLocals | true | Errors on unused local variables |
| noUnusedParameters | true | Errors on unused function parameters |
| allowUnreachableCode | false | Errors on unreachable code |
| allowUnusedLabels | false | Errors on unused labels |
| moduleDetection | "force" | Treats all files as ES modules |
| resolveJsonModule | true | Allows importing .json files as typed modules |
| noEmitOnError | true | Prevents emit when type errors are present |
| verbatimModuleSyntax | true | Preserves import/export syntax as written; implies isolatedModules |
| erasableSyntaxOnly | true | Forbids enums, namespaces, and parameter properties |
| target | "es2025" | Emits ES2025 JavaScript |
| lib | ["ES2025"] | Loads ES2025 built-in type declarations |
| skipLibCheck | true | Skips type checking of .d.ts files |
Library development
Extends base with emit settings for .d.ts generation and incremental builds.
| Option | Value | Effect |
| ------ | ----- | ------ |
| allowImportingTsExtensions | true | Allows .ts/.tsx extension imports in source |
| rewriteRelativeImportExtensions | true | Rewrites .ts/.tsx import extensions to .js/.jsx on emit |
| declaration | true | Emits .d.ts type declaration files |
| declarationMap | true | Emits source maps for .d.ts ("Go to Definition" navigates to source) |
| sourceMap | true | Emits .js.map source maps |
| isolatedDeclarations | true | Requires explicit type annotations on exports |
| composite | true | Enables project references and incremental compilation |
Library production
Extends library development; strips debug artifacts for smaller, cleaner output.
| Option | Value | Effect |
| ------ | ----- | ------ |
| sourceMap | false | Disables .js.map source maps |
| declarationMap | false | Disables .d.ts.map source maps |
| removeComments | true | Strips comments from emitted JavaScript |
| stripInternal | true | Removes @internal declarations from .d.ts output |
React JSX application
Extends base for React applications with DOM types and no-emit mode.
| Option | Value | Effect |
| ------ | ----- | ------ |
| allowImportingTsExtensions | true | Allows .ts/.tsx extension imports |
| noEmit | true | Disables emit; the bundler produces output |
| jsx | "react-jsx" | Uses the automatic JSX runtime (no import React needed) |
| lib | ["ES2025", "DOM", "DOM.Iterable", "DOM.AsyncIterable"] | Loads ES2025 plus DOM and iterable/async-iterable DOM declarations |
Vite + React JSX application
Extends the React JSX application preset with Vite-specific type declarations.
| Option | Value | Effect |
| ------ | ----- | ------ |
| types | ["vite/client"] | Loads Vite client types (import.meta.env, import.meta.hot, asset imports) |
Node
Extends base for Node.js tooling files, type-checked only — see Node preset for companion packages and execution guidance.
| Option | Value | Effect |
| ------ | ----- | ------ |
| allowImportingTsExtensions | true | Allows .ts extension imports |
| types | ["node"] | Loads Node.js global and built-in module types (requires @types/node) |
| noEmit | true | Disables emit; a runner or bundler executes the files |
Troubleshooting
error TS6053: File '@dvashim/typescript-config' not found— the package is not installed (or not resolvable from this project); run the install command from Installation.error TS2688: Cannot find type definition file for 'node'— the Node preset loads Node.js types; install@types/node.error TS2688: Cannot find type definition file for 'vite/client'— the Vite preset loads Vite's client types; installvitein the same package.TS2875/TS7026on JSX tags — the automatic JSX runtime can't find React's types; installreactand@types/react.error TS5011: … The 'rootDir' setting must be explicitly set— you added anoutDirto the base preset without arootDir; set"rootDir": "./src"(or your source root) alongside it. The library presets are unaffected (compositesupplies arootDir).tscis not found, or the editor falls back to its bundled TypeScript — thetypescriptpeer dependency is not installed; see Installation.- Stale errors or missing IntelliSense after install — restart the TS server after the first install or after changing
extends: in VS Code, run "TypeScript: Restart TS Server" from the Command Palette.
To see what a preset actually contributes, run npx tsc --showConfig: it prints your config with extends resolved, listing the options the presets set explicitly (TypeScript's own defaults are not shown).
Contributing
Issues and pull requests are welcome at dvashim/typescript-config. Security reports go through the security policy.
Development uses pnpm (version pinned via the packageManager field) on Node.js 24:
pnpm install
pnpm run check # format, package exports, and type-check every preset (plus emit smoke tests)The JSON presets in dist/ are the committed source of truth — edit them directly and update the matching test config in tests/. This project uses Changesets for versioning; run pnpm run changeset alongside changes to the presets in dist/ to describe them (dev-dependency, test, and doc changes don't need one). See the CHANGELOG for release history.
License
MIT © Aleksei Reznichenko
