How it works
Under the hood, tsgo-strict is a thin, fast coordinator around tsgo. It does five things on every run.
extends chain, pull the plugin block out of compilerOptions.plugins, and compute the project's source file list.rayon, check for pragmas, then apply paths / excludePattern. Pragmas win over config.extends yours with "strict": true enabled and files pinned to the selected subset.tsgo against the temp config, stream its diagnostics, and collect them in memory.tsc-style text, and exit with 0 / 1 / 2.Why this architecture
- One
tsgoinvocation, not one per file. Strict flags are applied at the project level; we just constrain which files get included in that project. - Filter at the input, not the output. We don't run the full project and grep for strict errors — that would still pay the full compile cost for all the loose files. Instead, we pin the
fileslist sotsgoonly loads the strict subset (plus its transitive type dependencies). - Pragma scanning is I/O-bound, so it goes parallel. Reading the first 4 KB of every source file in serial would dominate the runtime.
rayonparallelizes it across cores and drops ~1.5s to ~475ms on a 4000-file corpus (see Benchmarks).
Where "strict" comes from
The temporary tsconfig we emit forces "strict": true regardless of what your base tsconfig says. This matches the original typescript-strict-plugin, which overrides the same single setting on the language service host.
strict is the umbrella flag that TypeScript unfurls into the standard strict bundle: strictNullChecks, noImplicitAny, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables, and alwaysStrict. Optional-but-related knobs like noUncheckedIndexedAccess or exactOptionalPropertyTypes are not forced on — opt in via your own tsconfig if you want them.
Alongside strict, the temp config pins noEmit: true and applies a small set of TypeScript 6 compatibility shims so v6 default changes don't surface as new errors on code that was clean under v5. See Configuration › TypeScript 6 compatibility for the list. Everything else (module, target, jsx, paths, lib, …) is inherited from your base config.
Binary resolution
tsgo-strict drives the native TypeScript compiler (TypeScript 7 or later). When it needs one, it resolves a binary in this order and uses the first hit:
- The
TSGO_BINARYenvironment variable. - A platform-specific native binary from an installed distribution, found by walking up from the working directory:
@typescript/typescript-<platform>-<arch>/lib/tsc(TypeScript 7+), or@typescript/native-preview-<platform>-<arch>/lib/tsgo(the legacy preview). - The
binentry of an installedtypescript,@typescript/native-preview, ortsgopackage. tsgo, thentsc, onPATH.
It deliberately skips the node_modules/.bin wrapper scripts: they add Node startup overhead and can fail to resolve the native binary on some Node versions.
Rust distribution
The package ships as:
- An npm launcher (
@coralogix/tsgo-strict) containing the JS entry points and type definitions. - Per-platform subpackages (
@coralogix/tsgo-strict-<target>) containing the prebuilt binary + N-API addon for that platform, declared asoptionalDependencies.
npm / pnpm / yarn install exactly the subpackage matching your platform at install time. No compile step, no postinstall script.