Effect projects benefit from strict TypeScript configuration.
Key Settings Explained
Build Performance
"incremental": true,
"composite": true,- incremental - Fast rebuilds via .tsbuildinfo cache
- composite - Enables project references for monorepos
Module System
"target": "ES2022",
"module": "NodeNext",
"moduleDetection": "force",- ES2022 - Modern JS features (top-level await, etc)
- NodeNext - Proper ESM/CJS resolution
- force - Treats all files as modules
Import Handling
"verbatimModuleSyntax": true,
"rewriteRelativeImportExtensions": true,- verbatimModuleSyntax - Preserves import type syntax exactly
- rewriteRelativeImportExtensions - Allows .ts in imports
Type Safety
"strict": true,
"exactOptionalPropertyTypes": true,
"noUnusedLocals": true,
"noImplicitOverride": true,- strict - All strict checks enabled
- exactOptionalPropertyTypes - { x?: number } can't be { x: undefined }
- noUnusedLocals - Catch unused variables
- noImplicitOverride - Explicit override keyword required
Development
"declarationMap": true,
"sourceMap": true,
"skipLibCheck": true,- declarationMap - Jump-to-definition works for .d.ts
- sourceMap - Debugging support
- skipLibCheck - Faster builds (skip node_modules type checking)
Effect Integration
"plugins": [
{
"name": "@effect/language-service"
}
]Enables Effect language service for editor diagnostics. For build-time diagnostics, run bunx effect-language-service patch (see Project Setup).
Why These Settings?
- Performance - Incremental builds, composite projects
- Safety - Maximum type checking without escape hatches
- Modern - ESM-first, works with Node.js native modules
- DX - Source maps, declaration maps, Effect diagnostics
Module Settings by Project Type
The key difference between project types is the module and moduleResolution settings:
Bundled Apps (Vite, Webpack, esbuild, Rollup)
{
"compilerOptions": {
"module": "preserve",
"moduleResolution": "bundler",
"noEmit": true
}
}Use "module": "preserve" with "moduleResolution": "bundler" when a build tool handles module transformation. TypeScript acts as a type-checker only.
- Allows flexible import paths (with or without file extensions)
- Assumes bundler handles package.json exports/imports
- Used for frontend apps and any code processed by a bundler
Libraries & Node.js Apps
{
"compilerOptions": {
"module": "NodeNext"
}
}Use "module": "NodeNext" when TypeScript is your compiler. Required for:
- npm packages (libraries)
- Node.js apps (including those using Bun or other runtimes)
- CLI tools
This enforces Node.js module resolution rules:
- Requires .js file extensions in relative imports
- Respects package.json "type" and "exports" fields
- Works with both ESM and CommonJS
Additional library settings:
{
"compilerOptions": {
"declaration": true,
"composite": true, // monorepos only
"declarationMap": true // monorepos only
}
}Rule of thumb: Build tool compiling your code? Use preserve + bundler. TypeScript compiling your code? Use NodeNext.