include / exclude / files

Selects which source files enter the program, using globs, an allowlist, or a skip list.

Signature
{
  "files": string[],
  "include": string[],
  "exclude": string[]
}
  • Added in TypeScript 1.5

Parameters

ParameterTypeDescription
$filesoptionalstring[]= falseAn allowlist of exact file paths to include in the program. An error occurs if any of them cannot be found. Use it for a handful of files; use include when you need globs. Released in 1.5.
$includeoptionalstring[]= [] if files is specified; **/* otherwiseFilenames or glob patterns to include, resolved relative to the directory containing the tsconfig.json. `*` matches zero or more characters except a directory separator, `?` matches one such character, and `**/` matches any directory nested to any level. A last segment with no extension and no wildcard is treated as a directory. Released in 2.0.
$excludeoptionalstring[]= node_modules, bower_components, jspm_packages, and outDirFilenames or patterns skipped when resolving include. It filters include only — it does not prevent a file from entering the program. Released in 2.0.

Errors

A path listed in `files` that does not exist is an error. A config whose include/files pattern matches nothing raises TS18003, "No inputs were found in config file".

Changelog

  • PHP 2.0include and exclude added. Before this, a config either listed every file explicitly or compiled the whole directory.

These three settings choose the program's roots. Everything reachable from a root by an import, a types entry or a /// <reference> is pulled in on top, whether or not you named it.

Why exclude does not exclude

This is the single most reported non-bug. exclude filters what include finds — nothing more. A file under exclude still becomes part of the codebase if something imports it, if it is named in files, or if a reference directive points at it. It is not a mechanism that prevents a file from being compiled; delete the import, or move the file outside the project, if you truly want it gone.

The same asymmetry explains why node_modules types still get checked despite the default exclude: your code imports them.

Choosing between them

Reach for include for essentially every real project — ["src/**/*"] plus an exclude for tests or build output. Reach for files only for a small fixed list where a missing file should be a hard error, since files is checked, not globbed.

Glob details worth knowing

A pattern segment with no extension and no wildcard means a directory, and picks up .ts, .tsx and .d.ts — plus .js and .jsx when allowJs is on. And remember that when a config extends another, declaring any of these three replaces the base's version outright.

Example

Example · typescript
// tsconfig.json
//   { "include": ["src/**/*"], "exclude": ["src/legacy"] }

// src/legacy/money.ts — matched by exclude, compiled anyway
export const money = (cents: number) => `$${(cents / 100).toFixed(2)}`;

// src/checkout.ts — an include root, and it imports the "excluded" file
import { money } from "./legacy/money";

console.log("total:", money(4250));  // total: $42.50

// tsc pulls src/legacy/money.ts into the program through the import.
// exclude removed it from the include glob; the import put it straight back.

When to use it

  • Compile only src/ while keeping fixtures and build output out of the program
  • Split a tsconfig.build.json that excludes *.test.ts from the editor config that includes them
  • Pin a tiny declaration-only project to an exact file list so a missing file fails the build

Frequently asked questions

Why is TypeScript still compiling a file I put in exclude?

Because something imports it. exclude only filters the files that include would have matched; an import, a files entry, or a /// <reference> pulls the file back into the program regardless.

What is the difference between files and include?

files is an exact allowlist that errors when a listed path is missing, while include takes glob patterns and silently matches whatever exists — use files for a small fixed set, include for everything else.

What does tsc compile if I specify neither include nor files?

Everything: include defaults to **/* from the tsconfig.json's directory, minus the default exclude of node_modules, bower_components, jspm_packages and outDir.

More examples

files: an exact allowlist

The sorted join prints `solo:1 team:10` on every run. The interesting part is the config: with `files`, a path that no longer exists stops the build with TS6053 instead of quietly compiling a smaller program, which is what makes it worth using for small, deliberately fixed file sets.

Example · typescript
// tsconfig.json
// {
//   "files": ["src/index.ts", "src/types.ts"],
//   "compilerOptions": { "declaration": true, "outDir": "dist" }
// }
// A typo here — "src/typez.ts" — fails the build immediately:
//   error TS6053: File 'src/typez.ts' not found.

interface Plan { name: string; seats: number }

const plans: Plan[] = [
  { name: "team", seats: 10 },
  { name: "solo", seats: 1 },
];

console.log(plans.map(p => `${p.name}:${p.seats}`).sort().join(" "));
// solo:1 team:10

Two configs over one source tree

The log shows the file set the build config resolves to: only `src/cart.ts`. Note that tsconfig.build.json restates `include` even though it extends the editor config — include, exclude and files overwrite rather than merge, so the inherited `tests/**/*` would otherwise still be there, and the local `exclude` would not remove it.

Example · typescript
// tsconfig.json           — what the editor sees
// { "include": ["src/**/*", "tests/**/*"] }
//
// tsconfig.build.json     — what ships
// { "extends": "./tsconfig.json",
//   "include": ["src/**/*"],
//   "exclude": ["src/**/*.test.ts", "src/**/__fixtures__"] }

const files = [
  "src/cart.ts",
  "src/cart.test.ts",
  "tests/e2e.ts",
];
const shipped = files.filter(f => f.startsWith("src/") && !f.endsWith(".test.ts"));
console.log("build program:", shipped.join(", "));
// build program: src/cart.ts

Discussion

  • Be the first to comment on this lesson.