This section is based on The TSConfig Cheat Sheet article.
{
/* Workspace */
/* extends: the value of extends is a string which contains a path to another configuration file to inherit from. */
"extends": "./configs/base",
/* Source files */
/* files: specifies an allowlist of files to include in the program. An error occurs if any of the files can’t be found. */
"file": ["./main.ts"],
/* include: specifies an array of filenames or patterns to include in the program. These filenames are resolved relative to the directory containing the tsconfig.json file. */
"include": ["src/**/*"],
/* exclude: specifies an array of filenames or patterns that should be skipped when resolving include. */
"exclude": ["src/**/*.test.*"],
"compilerOptions": {
/* Base Options */
/* esModuleInterop: Helps mend a few of the fences between CommonJS and ES Modules. */
"esModuleInterop": true,
/* skipLibCheck: Skips checking the types of .d.ts files. This is important for performance, because otherwise all node_modules will be checked. */
"skipLibCheck": true,
/* target: The version of JavaScript you're targeting. I recommend es2022 over esnext for stability. */
"target": "es2022",
/* allowJs and resolveJsonModule: Allows you to import .js and .json files. Always useful. */
"allowJs": true,
"resolveJsonModule": true,
/* moduleDetection: This option forces TypeScript to consider all files as modules. This helps to avoid 'cannot redeclare block-scoped variable' errors. */
"moduleDetection": "force",
/* isolatedModules: This option prevents a few TS features which are unsafe when treating modules as isolated files. */
"isolatedModules": true,
/* verbatimModuleSyntax: This option forces you to use import type and export type, leading to more predictable behaviors and fewer unnecessary imports. With module: NodeNext, it also enforces you're using the correct import syntax for ESM or CJS. */
"verbatimModuleSyntax": true,
/* Strictness */
/* strict: Enables all strict type checking options. Indispensable. */
"strict": true,
/* noUncheckedIndexedAccess: Prevents you from accessing an array or object without first checking if it's defined. This is a great way to prevent runtime errors, and should really be included in strict. */
"noUncheckedIndexedAccess": true,
/* noImplicitOverride: Makes the override keyword actually useful in classes. */
"noImplicitOverride": true,
/* If transpiling with TypeScript: */
/* module: Tells TypeScript what module syntax to use. NodeNext is the best option for Node. moduleResolution: NodeNext is implied from this option. */
"module": "NodeNext",
/* outDir: Tells TypeScript where to put the compiled JavaScript files. dist is my preferred convention, but it's up to you. */
"outDir": "dist",
/* AND if you're building for a library: */
/* declaration: Tells TypeScript to emit .d.ts files. This is needed so that libraries can get autocomplete on the .js files you're creating. */
"declaration": true,
/* AND if you're building for a library in a monorepo: */
/* composite: Tells TypeScript to emit .tsbuildinfo files. This tells TypeScript that your project is part of a monorepo, and also helps it to cache builds to run faster. Referenced projects must have the new composite setting enabled. So if project A references project B, the latter must have "composite: true". In another words, every project that can be referenced by another (non-workspace) project must have "composite: true". */
"composite": true,
/* sourceMap and declarationMap: Tells TypeScript to emit source maps and declaration maps. These are needed so that when consumers of your libraries are debugging, they can jump to the original source code using go-to-definition. */
"sourceMap": true,
"declarationMap": true,
/* declaration: Tells TypeScript to emit .d.ts files. This is needed so that libraries can get autocomplete on the .js files you're creating. */
"declaration": true,
/* If NOT transpiling with TypeScript: */
/* module: preserve is the best option because it most closely mimics how bundlers treat modules. moduleResolution: Bundler is implied from this option. */
"module": "preserve",
/* noEmit: Tells TypeScript not to emit any files. This is important when you're using a bundler so you don't emit useless .js files. */
"noEmit": true,
/* If your code runs in the DOM: */
/* lib: Tells TypeScript what built-in types to include. es2022 is the best option for stability. dom and dom.iterable give you types for window, document etc. */
"lib": ["es2022", "dom", "dom.iterable"],
/* If your code doesn't run in the DOM: */
/* lib: Tells TypeScript what built-in types to include. es2022 is the best option for stability. */
"lib": ["es2022"],
/* Modules */
/* baseUrl: sets a base directory from which to resolve bare specifier module names. With "baseUrl": "./", TypeScript will look for files starting at the same folder as the "tsconfig.json". So "hello/world" resolves to "./hello/world". This resolution has higher priority than lookups from "node_modules".*/
"baseUrl": "./",
/* module: tells compiler what kinds of modules the host expects, so TypeScript can set its output format for each file to match. You very likely want "nodenext" for modern Node.js projects and preserve or esnext for code that will be bundled. */
"module": "es2020",
/* moduleResolution: specify the module resolution strategy. 'node16' or 'nodenext' for modern versions of Node.js to support both ECMAScript imports and CommonJS require, resolved using different algorithms. 'node10' (previously called 'node') only supports CommonJS require. 'bundler' for use with bundlers and does not require file extensions on relative paths in imports.*/
"moduleResolution": "nodenext",
/* path: specifies a series of entries which re-map imports to lookup locations relative to the baseUrl */
"paths": {
"@app/*": ["./src/*"],
"tests/*": ["./src/tests/*"],
"https://esm.sh/lodash@4.17.21": [
"./node_modules/@types/lodash/index.d.ts"
]
},
/* resolveJsonModule: Allows importing modules with a .json extension */
"resolveJsonModule": true,
/* rootDir: defines the common directory where all codes are organised. rootDir does not affect which files become part of the compilation. It has no interaction with the include, exclude, or files tsconfig.json settings. */
"rootDir": "./src",
/* rootDirs: As alternative to rootDir, using rootDirs, the compiler becomes aware of the “virtual” directories acting as a single root and resolves relative module imports within these “virtual” directories, as if they were merged in to one directory. This is useful to separate the type definitions of non-code (CSS, HTML, JSON, etc) files that are being imported into the code (js, ts, jsx, tsx, etc) files.*/
"rootDirs": ["src", "generated-types"],
/* typeRoots: if not specified, all type definitions from node_modules/@types are visible to TS. Otherwise, only packages under typeRoots folders will be included. */
"typeRoots": ["./typings", "./vendor/types"],
/* type: if specified, only packages with the name listed will be included in the global scope. This does not affect importing a module that has its type definition. It only affects the globals (definitions such as `process` in node or `expect` in Jest) */
"types": ["node", "jest", "express"],
/* outDir: if not specified, .js files are emitted in the same directors as the source. Otherwise, it specified the output folder with the directory structure similar to the original source files. */
"outDir": "dist",
/* outFile: if specified, all global (non-module) files will be concatenated into the single output file specified. */
"outFile": "output",
/* JS Support */
/* allowJs: allow JavaScript files to be imported inside your project. */
"allowJs": true,
/* checkJs: working in tandem with allowJs, when checkJs is enabled then errors are reported in JavaScript files. */
"checkJs": true,
/* React */
/* jsx: controls how JSX constructs are emitted in JavaScript files. */
"jsx": "react-jsx",
/* jsxFactory: changes the functions in the output .js file replacing the original JSX syntax. */
"jsxFactory": "h",
/* jsxFragmentFactory: specifies the JSX fragment factory function to use when targeting react JSX emit with jsxFactory compiler option is specified. */
"jsxFragmentFactory": "Fragment",
/* jsxImportSource: declares the module specifier to be used for importing the jsx and jsxs factory functions when using jsx as "react-jsx" or "react-jsxdev"*/
"jsxImportSource": "react-jsx",
/* Libraries */
/* lib: by default TS include the type definition for built-in JS APIs. To change the default setting, you can add the list of all required libraries*/
"lib": ["ESNext", "DOM", "WebWorker", "ScriptHost"],
/* Target */
/* target: changes which JS features are downleveled and which are left intact*/
"target": "es2023",
/* Diagnostics */
/* diagnostics: outputs diagnostic information for debugging. */
"diagnostics": true,
/* explainFiles: print names of files which TypeScript sees as a part of your project and the reason they are part of the compilation. */
"explainFiles": true,
/* extendedDiagnostics: includes information about where TS is spending time when compiling. */
"extendedDiagnostics": true,
/* generateCpuProfile: to ask TypeScript to emit a v8 CPU profile during the compiler run.*/
"generateCpuProfile": true,
/* generateTrace: generates an event trace and a list of types. */
"generateTrace": true,
/* listEmittedFiles: print names of generated files part of the compilation to the terminal. */
"listEmittedFiles": true,
/* listFiles: print names of files part of the compilation. */
"listFiles": true,
/* noCheck: disables full type checking (only critical parse and emit errors are reported). */
"noCheck": true,
/* traceResolution: to have TypeScript print information about its resolution process for each processed file.*/
"traceResolution": true,
/* Project */
/* incremental: creates a series of .tsbuildinfo that helps with incremental compilation. */
"incremental": true,
/* When creating multiple subproject (eg. in a monorepo), each individual project can be included in the main tsconfig.json file. The path property of each reference can point to a directory containing a tsconfig.json file, or to the config file itself (which may have any name). */
"reference": [
{
"path": "./server"
},
{
"path": "tsconfig.client.ts"
}
]
}
}This configuration model is useful when working with Vite (adopted from Vue project configuration).
{
"compilerOptions": {
"lib": [
// Target ES2020 to align with Vite.
// <https://vite.dev/config/build-options.html#build-target>
// Support for newer versions of language built-ins are
// left for the users to include, because that would require:
// - either the project doesn't need to support older versions of browsers;
// - or the project has properly included the necessary polyfills.
"ES2020",
"DOM",
"DOM.Iterable"
// No `ScriptHost` because Vue 3 dropped support for IE
],
// Set to empty to avoid accidental inclusion of unwanted types,
// e.g. the Node.js types that would pollute the global scope.
"types": [],
// Most non-library projects don't need to emit declarations.
// So we add this option by default to make the config more friendly to most users.
"noEmit": true,
// As long as you are using a build tool, we recommend you to author and ship in ES modules.
// Even if you are targeting Node.js, because
// - `CommonJS` is too outdated
// - the ecosystem hasn't fully caught up with `Node16`/`NodeNext`
// This recommendation includes environments like Vitest, Vite Config File, Vite SSR, etc.
"module": "ESNext",
// We expect users to use bundlers.
// So here we enable some resolution features that are only available in bundlers.
"moduleResolution": "bundler",
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
// Even files without `import` or `export` are treated as modules.
// It helps to avoid mysterious errors such as `Cannot redeclare block-scoped variable 'name`.
// https://www.totaltypescript.com/cannot-redeclare-block-scoped-variable#solution-3-your-module-isnt-a-module
"moduleDetection": "force",
// Required in Vue projects
"jsx": "preserve",
"jsxImportSource": "vue",
// `"noImplicitThis": true` is part of `strict`
// Added again here in case some users decide to disable `strict`.
// This enables stricter inference for data properties on `this`.
"noImplicitThis": true,
"strict": true,
// See <https://www.semver-ts.org/formal-spec/5-compiler-considerations.html#strictness>
// These 2 options are also part of the recommended tsconfig as of TS 5.9
"noUncheckedIndexedAccess": true,
// Commented out for now. It's hard to land in the current ecosystem.
// Needs more consensus before moving forward.
// "exactOptionalPropertyTypes": true,
// <https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#verbatimmodulesyntax>
// Any imports or exports without a type modifier are left around. Also verbatimModuleSyntax is a superset of isolatedModules and is needed, because Vite uses esbuild for transpiling TypeScript and is subject to single-file transpile limitations.
"verbatimModuleSyntax": true,
// A few notes:
// - Vue 3 supports ES2016+
// - For Vite, the actual compilation target is determined by the
// `build.target` option in the Vite config.
// So don't change the `target` field here. It has to be
// at least `ES2020` for dynamic `import()`s and `import.meta` to work correctly.
// - If you are not using Vite, feel free to overwrite the `target` field.
"target": "ESNext",
// For spec compliance.
// `true` by default if the `target` is `ES2020` or higher.
// Explicitly set it to `true` here in case some users want to overwrite the `target`.
"useDefineForClassFields": true,
// Recommended
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"libReplacement": false,
// See <https://github.com/vuejs/vue-cli/pull/5688>
"skipLibCheck": true
}
}{
"$schema": "https://www.schemastore.org/tsconfig",
"_version": "24.0.0",
"compilerOptions": {
"lib": [
"es2024",
"ESNext.Array",
"ESNext.Collection",
"ESNext.Error",
"ESNext.Iterator",
"ESNext.Promise"
],
"module": "nodenext",
"target": "es2024",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node16"
}
}Here, it is assumed that frontend is not aware of backend and they are not referring each other.
{
"extends": "./tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.ts"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
// Extra safety for array and object lookups, but may have false positives.
"noUncheckedIndexedAccess": true,
// Path mapping for cleaner imports.
"paths": {
"@/*": ["./src/*"]
}
}
}// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping.
{
"extends": "./tsconfig/tsconfig.node.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*",
"eslint.config.*"
],
"compilerOptions": {
// Most tools use transpilation instead of Node.js's native type-stripping.
// Bundler mode provides a smoother developer experience.
"module": "preserve",
"moduleResolution": "bundler",
// Include Node.js types and avoid accidentally including other `@types/*` packages.
"types": ["node"],
// Disable emitting output during build, which is used for type-checking only.
"noEmit": true
}
}{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}This configuration model is useful when working with Turborepo (adopted from bhvr project configuration).
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}{
"extends": "../tsconfig.json",
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.app.json" }
]
}{
"extends": "../tsconfig.json",
"compilerOptions": {
// Environment settings
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx",
// Types
"types": ["bun-types"],
// Output settings
"declaration": true,
"outDir": "dist",
"noEmit": false,
"emitDecoratorMetadata": true,
// Module resolution
"moduleResolution": "bundler",
"allowImportingTsExtensions": false
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}{
"extends": "../tsconfig.json",
"compilerOptions": {
// Environment setup
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
// Output configuration
"declaration": true,
"outDir": "./dist",
"noEmit": false,
// Type checking
"strict": true,
"skipLibCheck": true,
// Additional checks
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.test.ts", "dist"]
}{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Module resolution
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"verbatimModuleSyntax": true,
// Strictness and best practices
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"experimentalDecorators": true,
// Output control
"skipLibCheck": true,
// Optional strict flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}