npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

angular-typechecker

v0.2.0

Published

Nx executor that runs the complete Angular compiler type-check (TypeScript + template type-check + extended NG8xxx diagnostics), no emit, decoupled from build and test.

Downloads

1,050

Readme

angular-typechecker

npm version npm downloads license CI

The complete Angular compiler type-check as a cacheable Nx target that does not build or emit.

angular-typechecker runs the full Angular compiler diagnostic set over a project and reports what it finds. It is built for the loops the editor does not cover: CI, pre-commit, and AI coding agents that need a static check on demand.

  • Runs Angular's full diagnostic set (TypeScript, template type-checking, and extended NG8xxx) in one pass, not just tsc.
  • Emits nothing and builds nothing: no bundler, no test runner, no output files.
  • Covers applications and every library kind (local/non-buildable, buildable, publishable), and checks the spec tsconfig in the same run.
  • Runs as a cacheable Nx target, so unchanged projects are skipped on re-runs.
  • Prints deterministic, ANSI-free output and exits non-zero on any error, so CI jobs and agents can gate on pass/fail directly.

It is a type-checker, not a build, a linter, or a test runner, and it does not replace your editor's Angular Language Service. It is the headless check you run everywhere the editor is not.

Contents

What it does

For each project, angular-typechecker walks the solution tsconfig.json down to its in-project leaves (the app or lib tsconfig and tsconfig.spec.json) and runs the Angular compiler with no emit. It gathers diagnostics from every phase (option, syntactic, semantic, template, and extended NG8xxx) in one unconditional pass, so a template or NG8xxx problem still surfaces even when a TypeScript error sits in the same file. A bare ngc --noEmit stops at the first failing phase and can bury the rest.

Requirements

| Tool | Supported version | | --------------------------------------- | ------------------------------------- | | Nx | 23.x | | Angular (@angular/compiler-cli, peer) | 22.x stable (^22.0.0) | | TypeScript (peer) | >=6.0.0 <6.1.0 | | Node | ^22.22.3 \|\| ^24.15.0 \|\| ^26.0.0 |

@nx/devkit ships as a pinned dependency, so you never declare it yourself. You provide @angular/compiler-cli and typescript, the versions your workspace already uses.

Note: the ^22.0.0 peer range excludes Angular 22 pre-releases (-next / -rc) by semver rules. To run the plugin on a 22.x pre-release, install with --legacy-peer-deps, which relaxes peer resolution for the whole install, so use it sparingly. The TypeScript window is narrow on purpose: Angular 22 supports only TypeScript 6.0.x. The range may widen later; widening is non-breaking under 0.x semver.

Installation

nx add angular-typechecker

nx add installs the package and runs its init generator, which seeds a cacheable angular-typechecker:typecheck entry into nx.json targetDefaults.

Prefer plain npm? Install the package and run init yourself:

npm install --save-dev angular-typechecker
nx g angular-typechecker:init

In a pnpm workspace, add it to the workspace root and run init the same way:

pnpm add -Dw angular-typechecker
nx g angular-typechecker:init

This is nx add, not the Angular CLI's ng add, and there is no Angular-CLI installer.

Quick start

Wire a project with the configuration generator, then run the target:

nx g angular-typechecker:configuration my-app
nx typecheck my-app

The generator adds a single typecheck target pointed at the project's solution tsconfig.json. Because the engine walks that tsconfig's leaves, the spec tsconfig is checked in the same run, so you never add a second target. Two flags matter:

  • --tsConfig <path> points the target at a different tsconfig. It defaults to the solution tsconfig.json and falls back to tsconfig.app.json / tsconfig.lib.json when the project has no solution tsconfig with project references.
  • --targetName <name> names the target something other than typecheck.

Re-running the generator is safe: it will not overwrite a target of the same name that is not ours.

Wiring a project by hand

To skip the generator, add the target yourself. Point it at the solution tsconfig.json and reference the published executor id angular-typechecker:typecheck:

{
  "targets": {
    "typecheck": {
      "executor": "angular-typechecker:typecheck",
      "options": {
        "tsConfig": "apps/my-app/tsconfig.json",
      },
    },
  },
}

Then add the cacheable targetDefaults entry to nx.json (this is what init seeds). Its inputs are what make the whole-program check cache correctly: they cover non-buildable dependency sources via ^default and buildable dependency outputs via dependentTasksOutputFiles:

{
  "targetDefaults": {
    "angular-typechecker:typecheck": {
      "cache": true,
      "outputs": [],
      "inputs": [
        "default",
        "{projectRoot}/tsconfig*.json",
        "{projectRoot}/package.json",
        "{workspaceRoot}/tsconfig.base.json",
        "^default",
        {
          "dependentTasksOutputFiles": "**/*.{d.ts,d.cts,d.mts,tsbuildinfo}",
          "transitive": true,
        },
        {
          "externalDependencies": ["typescript", "@angular/compiler-cli"],
        },
      ],
    },
  },
}

One thing to get right: the first input must be default, not production. production drops *.spec.ts, which would under-hash the spec sources the check covers, so a spec-only edit could then reuse a stale cache and pass when it should fail.

Executor options

| Option | Type | Default | Description | | ------------- | ------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | tsConfig | string | (required) | Path to the tsconfig to type-check. Resolved relative to the workspace root when not absolute. | | includeDeps | boolean | false | Include out-of-project and node_modules diagnostics. The default excludes them (project-in-isolation). | | maxWarnings | number | (unset) | Fail when the warning count exceeds this number. 0 fails on any warning. A dropped warning on an uncovered first-party file counts toward this total too. Omit to never fail on warnings alone. | | failFast | boolean | false | Report only the first error (output brevity). Not a speed-up; all diagnostics are still gathered. | | strict | boolean | false | Controls what a first-party file the check couldn't fully cover does to the run. Default (off): a file with an error fails the run; one with only warnings just prints a notice, though a dropped warning still counts toward maxWarnings. On: a warning-only file fails regardless of maxWarnings (a file with an error still fails). It only adds a fail path; it never turns a failure into a pass. See Partial coverage. |

Partial coverage

The check runs a project in isolation, so a few situations leave a first-party file not fully covered. It always tells you when that happens; whether the run fails depends on the case, as described below.

  • A first-party file imported from source that the checked tsconfig doesn't declare. When your project imports an internal workspace library from source (often through a TypeScript paths alias), the compiler pulls that file in and checks it, but it belongs to another project, so its diagnostics are dropped from your report and you see your own errors, not the library's. An error in such a file fails the run; a warning on it just prints a notice unless you gate warnings with maxWarnings or turn on strict. To see the error reported directly, run that library's own typecheck target, or set includeDeps: true to fold these diagnostics back into your report.
  • A referenced config that declares no files: an empty config, or a tsconfig that only points at other projects (the check follows one level of references). This fails the run rather than passing over something it never checked. Out-of-project, duplicate, and self references are skipped with a warning and don't change the result; point tsConfig at that config directly if you need it checked.
  • A fatal template error (NG3004) stops Angular's template type-checking for the whole program, which hides other files' template and NG8xxx diagnostics until you fix it. The run exits non-zero and tells you its results are incomplete.
  • A declared file the check can't type-check, which is advisory and does not fail the run: .mdx is never type-checked, and a .tsx is checked only when your tsconfig sets compilerOptions.jsx. The run prints a notice naming these files and stays green. See notTypeCheckedDeclaredFiles under Programmatic API.

The opt-in strict option extends the first case: it makes a warning-only uncovered file fail the run too, so any first-party file the check couldn't fully cover fails.

Output

angular-typechecker prints one format: the Angular compiler's formatDiagnostics, a superset of tsc that renders NG codes and template code frames, written straight to stdout. A run with a TypeScript error and an Angular template diagnostic looks like this:

libs/ui/src/lib/greeting.component.ts:8:38 - error TS2322: Type 'number' is not assignable to type 'string'.

8   protected readonly label: string = 0;
                                       ~
libs/ui/src/lib/greeting.component.html:1:6 - error NG8002: Can't bind to 'srcc' since it isn't a known property of 'img'.

1 <img [srcc]="label" />
       ~~~~~~~~~~~~~~

Each diagnostic is path:line:column - severity CODE: message, followed by a code frame. The report can carry three kinds of finding, all in the same run:

  • Plain TypeScript diagnostics (TS2322 and the rest of the TSxxxx set).
  • Angular template type-check diagnostics, from checking template expressions and bindings against component types, such as NG8002 above.
  • Angular extended diagnostics: the stricter, opt-in template checks, such as NG8101 (an invalid banana-in-a-box binding) or NG8109 (a signal not invoked in a template).

Three things shape the output:

  • Color is auto-detected from stdout.isTTY and stripped off-TTY (CI, pipes, agents), so captured logs stay ANSI-free.
  • failFast cuts the reported list off at the first error. It shortens output only; every diagnostic is still gathered.
  • Paths are workspace-root-relative, so they line up with a standard file:line:col problem matcher (see Continuous integration).

Machine-readable reporters (JSON, SARIF) are a deliberate non-goal in v0.x; the human-readable format above is the only output.

Exit codes

The executor reports a pass/fail result that Nx maps to the process exit code, so a CI step or an agent can gate on pass/fail directly:

  • Exit 0: no error-category diagnostics were reported, and the warning count is within maxWarnings.
  • Non-zero: at least one error-category diagnostic was reported, or the warning count exceeded maxWarnings.
  • Non-zero: the Angular compiler failed to run at all (an infrastructure error, such as a missing or unreadable tsconfig). This is logged distinctly from a type error, because a type-checker that reports success on its own crash is worse than none.

The exit code signals only pass or fail. To tell a type error, a warning-threshold failure, and an infrastructure error apart, read the output.

Continuous integration

Since the target exits non-zero on an error, a CI step that runs nx typecheck <project> fails the job on any type or template error with no extra scripting. Run it across only the projects a change touches with nx affected -t typecheck.

The workspace-relative file:line:col paths also let GitHub Actions annotate each diagnostic inline. Because the output is a tsc superset, one tsc-style problem matcher catches both TypeScript (TSxxxx) and Angular (NGxxxx) codes. Drop this in .github/matchers/tsc.json:

{
  "problemMatcher": [
    {
      "owner": "angular-typechecker",
      "pattern": [
        {
          "regexp": "^(\\S.*?):(\\d+):(\\d+)\\s+-\\s+(error|warning)\\s+((?:TS|NG)\\d+):\\s+(.*)$",
          "file": 1,
          "line": 2,
          "column": 3,
          "severity": 4,
          "code": 5,
          "message": 6
        }
      ]
    }
  ]
}

Register it right before the target runs:

- run: echo "::add-matcher::.github/matchers/tsc.json"
- run: npx nx typecheck my-app

Programmatic API

Nx loads the executor and the generators by path, so most consumers never import the package directly. When you do need to run the check from code, the package exports a small barrel:

import { runTypecheck, TypecheckInfrastructureError } from 'angular-typechecker';
import type { CoreOptions, CoreResult, SkippedReference } from 'angular-typechecker';

// tsConfigPath must be absolute. runTypecheck does not resolve it for you.
const options: CoreOptions = {
  tsConfigPath: '/abs/path/to/apps/my-app/tsconfig.json',
  includeDeps: false, // set true to include out-of-project + node_modules diagnostics
};

try {
  const result: CoreResult = await runTypecheck(options);
  // result: { tsConfigPath, rootNamesCount, diagnostics: readonly ts.Diagnostic[],
  //   errorCount, warningCount, suppressedThirdParty, suppressedInGraphErrorCount,
  //   suppressedInGraphWarningCount, suppressedInGraphFiles: readonly string[],
  //   durationMs, templateCheckAborted?,
  //   skippedReferences?: readonly SkippedReference[],
  //   notTypeCheckedDeclaredFiles?: readonly string[],
  //   bundlerQueryImports?: readonly string[] }
  process.exitCode = result.errorCount > 0 ? 1 : 0;
} catch (error) {
  if (error instanceof TypecheckInfrastructureError) {
    // the compiler crashed (code 500): an infrastructure failure, not a type error
  }

  throw error;
}

runTypecheck hands back the raw counts and diagnostics and leaves the verdict and rendering to you. maxWarnings, failFast, and color live in the executor, not the barrel, and the engine internals (compiler loader, gatherer, boundary filter, formatter) stay unexported.

How it compares

Angular builds already type-check, but they tie that check to emit. Fast dev pipelines skip it on purpose. Per-file compilers (AnalogJS fastCompile, the experimental Oxc compiler) and esbuild dev trade the whole-program check for speed and tell you to run it elsewhere; in the editor, the Angular Language Service handles the live loop. This plugin is that "elsewhere" for headless CI and agent loops.

  • Compared with ngc --noEmit: ngc short-circuits by phase, so a TypeScript error can mask template and NG8xxx diagnostics. angular-typechecker gathers every phase in one pass (in the spirit of @angular/build), so an ordinary TypeScript error never masks the template and NG8xxx diagnostics.
  • Compared with Nx's @nx/js typecheck target: that runs plain tsc / tsgo, which Angular projects cannot use (Angular has no TypeScript project-references support) and which never sees template or NG8xxx diagnostics anyway.

For the background on why the whole-program type-check is the dominant, separable cost of an Angular build, see Brandon Roberts' Angular Compilation, Type-Checking, and Build Bottlenecks (2026).

Storybook

nx typecheck type-checks your Storybook stories with no extra setup. Storybook's TypeScript files (your *.stories.ts, .storybook/main.ts, and .storybook/preview.ts) are just more files your project's tsconfig includes, so the tool checks them the same way it checks the rest of your project. There is no Storybook-specific option or flag, and the plugin has no dependency on Storybook.

You get the complete Angular check on every TypeScript file your Storybook tsconfig declares: TypeScript errors plus template and NG8xxx diagnostics, with no emit. A passing run means all of those files type-checked cleanly. One thing makes this work, and the configuration generator already sets it up for you. Point the typecheck target at your project's top-level tsconfig.json, the one with a references array, not at a specific tsconfig.app.json / tsconfig.lib.json. The tool follows those references to find your stories, so a single leaf config leaves the stories out. Order doesn't matter: the target reads the references each time it runs, so adding Storybook after you wire typecheck works on the next run, with no re-generation.

This covers both ways teams set up Storybook in an Nx workspace:

  • A Storybook in each project (nx g @nx/angular:storybook-configuration): that project's stories are checked.
  • One central Storybook for the whole workspace (the Nx "one Storybook for all projects" recipe, where a single Storybook pulls in stories and components from many projects): the files its tsconfig declares are checked too, and a first-party file reached only through an import is surfaced as incomplete coverage rather than skipped. A real error in any of them fails the run.

Storybook Composition

Storybook Composition (one Storybook that embeds other, independently built Storybooks) is a project structure, not a special tsconfig. Each composed project and the composing host are ordinary per-project Storybooks, so you check them the normal way: give each project its own typecheck target and run them together with nx run-many -t typecheck or nx affected -t typecheck. To check a host and everything it composes in one command, add dependsOn: ["^typecheck"] to the host's typecheck target and list the composed projects in the host's implicitDependencies.

This checks each project's own TypeScript, including the host's .storybook/main.ts, so a real TypeScript error in its refs object is reported. It does not verify that the composed refs URLs resolve or deploy; those are runtime URLs, not TypeScript. Note that @storybook/angular types the refs object loosely (as any), so a mistyped refs value is caught only if you annotate it with your own type.

What this does and doesn't promise

It type-checks the TypeScript files your Storybook tsconfig declares. It does not claim to cover every Storybook file, and it does not verify that Storybook builds or runs. It is a type-check, nothing more. Setups other than the two above aren't officially supported. When it can't fully check a first-party file it says so; whether that fails the run depends on the case (see Partial coverage).

Things to know

  • .mdx docs are never type-checked, and a .tsx story is checked only when your tsconfig sets compilerOptions.jsx. When your Storybook config declares files like these that can't be checked, nx typecheck prints a notice naming them; this never changes whether the run passes. See notTypeCheckedDeclaredFiles under Programmatic API.

  • Stories that use an external templateUrl are handled. A template error such as NG8002 is reported against the right component, not dropped.

  • Vite and Analog Storybook ?query imports: add "types": ["vite/client"] to the tsconfig you check. That one line is the fix. Imports like import src from './x?raw' (and ?url, ?worker, ?inline, and virtual modules) are Vite features TypeScript doesn't understand on its own, so the Angular compiler reports them as TS2307 ("cannot find module"). Adding "vite/client" declares that whole family of imports and clears the errors. In one real project it took the count from 227 such errors to zero without hiding any genuine problem: a truly missing module, or the wrong type of value, still fails. This applies whether your Storybook builds with webpack/esbuild (@storybook/angular) or Vite (@analogjs/storybook-angular). It is standard TypeScript behavior for Vite projects, not something specific to this tool.

    If you'd rather not depend on Vite's types, declare the imports yourself in a .d.ts your tsconfig includes, one per suffix (declare module '*?raw' { const src: string; export default src; }). This only covers the suffixes you list, so "vite/client" is preferred. Either way there is one narrow blind spot: a ?query import of a base file that doesn't exist won't be flagged, the same gap between building and type-checking that Vite itself has.

    The tool never hides these TS2307 errors automatically, because a missing module can be a real bug. When it sees unresolved ?query imports it lists them in a notice that points you at this same fix and goes quiet once they resolve (see bundlerQueryImports under Programmatic API).

  • Point the target at your top-level tsconfig.json, not a tsconfig.app.json / tsconfig.lib.json. A leaf config leaves the stories out.

  • A single flat tsconfig.json with no references isn't an officially supported Storybook setup. Pointed at a flat config directly, the tool checks the stories that config includes; a config that declares no files fails the run instead of passing with nothing checked.

  • The Angular CLI Storybook setup (ng add @storybook/angular, which wires its tsconfigs through angular.json with no top-level references) is not supported.

  • Installing Storybook on Angular 22 needs a peer-dependency override. @storybook/[email protected] still caps its Angular peer at >=18 <22 (TypeScript ^4.9 || ^5), so you need --legacy-peer-deps (or --force) to install it on Angular 22 / TypeScript 6; on pnpm, nx add can hit ERR_PNPM_IGNORED_BUILDS. This is a Storybook install constraint, not an angular-typechecker one; the tool applies no version gate. That Storybook version also emits 48 TypeScript 6 errors from its own bundled type declarations. Those come from node_modules and never affect your result, while genuine errors in your own main.ts / preview.ts are still reported.

Limitations

  • angular-typechecker is 0.x (pre-1.0). Breaking changes are allowed in minor releases under the project's 0.x semver policy.
  • Some first-party files can't be fully covered when a project is checked in isolation; see Partial coverage for the cases and how to control them.
  • Machine-readable reporters (JSON, SARIF) and a standalone CLI are non-goals in v0.x.

Contributing

Issues and pull requests are welcome on GitHub. Please open an issue to discuss a substantial change before sending a pull request.

License

MIT (c) 2026 Lars Gyrup Brink Nielsen