Skip to content

Findings & notices

A finding is a real problem that fails the audit (ok: false, exit 1). A notice is a coverage gap that does not fail by default. An unchecked specifier is one static analysis could not resolve (surfaced for transparency, never a failure).

Every finding has a surface (types or runtime) and a kind:

KindSurfaceMeaning
undeclaredtypes / runtimeThe owning package is reachable on the surface but is not declared in any non-dev manifest field.
missing-typestypesThe package is declared but provides no resolvable declarations for the specifier (the headline bug — e.g. a .d.ts import('react') with react declared but no @types/react).
unresolvedruntimeThe package is declared but the specifier does not resolve to a file — typically a deep import of a subpath the dependency’s exports does not expose, or a missing target file.

Each finding carries a suggestion with concrete remediation. Examples:

✗ types [undeclared] csstype (dist/index.d.ts)
→ declare "csstype" (or "@types/csstype" if it ships no types)
✗ types [missing-types] react (dist/index.d.ts)
→ "react" is declared but provides no resolvable declarations for "react"; add "@types/react" or a version that ships types
✗ runtime [unresolved] exporter/private (dist/index.js)
→ "exporter/private" does not resolve through declared "exporter" (subpath not exported, or the target file is missing)
  • undeclared (runtime): add the package to dependencies (or peerDependencies/optionalDependencies if that fits its role).
  • undeclared (types): add the package — or its @types/* companion if it ships no types of its own — to dependencies (runtime-needed) or devDependencies is not enough if the type leaks into your published .d.ts; a type a consumer must resolve has to be a non-dev dependency.
  • missing-types: declare the @types/* package, or upgrade the dependency to a version that bundles its own declarations.
  • unresolved: stop importing the private subpath, or (if it should be public) ask the dependency to add it to its exports. If it is your own subpath import that the dependency genuinely exports, this can indicate a version mismatch in the materialized tree.

A node:-prefixed or bare builtin (fs, path, …) needs no declaration at run time, so it is never a runtime finding. On the type surface a builtin implies @types/node: if a declaration references a builtin and @types/node is not declared, that is an undeclared finding suggesting @types/node.

A notice means a surface had nothing to analyze — emitted so “audited, clean” is never confused with “nothing audited”. Notices live in result.notices, print as , and do not fail the audit unless you pass --require-types.

KindSurfaceMeaning
types-not-builttypesThe manifest declares type declarations (a types/typings field, typesVersions, or an exports types condition) but none resolve from the package root — the build output looks missing. Build the package before auditing, or fix the declared types path.
types-unreachabletypesThe package ships .d.ts files but no manifest entry exposes them (no types field, no exports types condition, and exports encapsulates the package). Consumers cannot resolve its types — a likely packaging gap.

A package that legitimately declares and ships no types (e.g. a Babel/PostCSS plugin) produces no notice. A fully-analyzed type surface produces no notice.

Pass --require-types (CLI) to promote any coverage notice to a failure (exit 1) — useful in a monorepo gate where every TypeScript package is expected to ship resolvable types. Programmatically, inspect result.notices.length yourself.

A specifier whose value is not a literal — a dynamic import(someVariable), a templated require() call, a createRequire result stored in a variable — cannot be statically resolved. Rather than drop it (a silent false negative), the tool records it in result.unchecked with a reason, printed as ?. Review these manually; they are not failures.

Some findings are intentional — an optional/plugin import the code guards at run time, or a specifier static analysis cannot prove is fine. Suppress them with ignore rules (CLI --ignore, or a config file). Suppressed findings move to result.ignored, still print (— ignored), and never fail the audit — so suppressions stay auditable.

An IgnoreRule matches a finding when every field it sets equals the finding’s; an empty rule matches nothing:

{ "package": "optional-plugin" } // any finding for this package
{ "specifier": "react/jsx-runtime", "surface": "types" } // this exact specifier, on the type surface
{ "surface": "runtime", "kind": "unresolved" } // all unresolved runtime findings

A CLI --ignore <value> is shorthand for “match package === value OR specifier === value”.