Rule 12.4
On this page

Rule 12.4

Chapter 12, Diagnostics Test

One mistake reads as one diagnostic; a refusal must not be followed by further diagnostics about the same mistake.

The rule text and the parts under it are the compiler's own English, as the design document writes them.

Rationale

a cascade hides the sentence that says what to do.

Derives from

surface §28 (“and one mistake reads as one sentence”).

How it is verified

Checked by a test. A test, a gate script or a CI workflow names this rule, and the traceability check fails when a file listed below stops naming it.

Where the rule says the compiler enforces it:

honest-refusals.test.ts (one mistake reads as one sentence), for the surface §28 shapes, and (a refused declaration is the one diagnostic for its name), for a refused declaration: a read of the name, an assignment to it or a write through it reports nothing more when an error stands inside the declaration the name resolves to or inside a declaration that one reads (a local declared from a refused one), while a name read out of its scope, read before its declaration or declared nowhere still reports TS8022 (src/compiler/ts/refused-names.ts, #171); and, across the language service’s two halves, mergeDiagnostics (src/language-service/diagnostics.ts), which keeps the compiler’s diagnostic where TypeScript and the compiler report one mistake, with no exception (a misspelled name included, since the compiler names the fix itself under Rule 12.1), and drops TypeScript’s knock-on of a value it could not type itself (a call it failed to resolve, a name or a member it cannot find), reached directly, through a local declared with no type or through an operation, in src/language-service/diagnostics.test.ts (one mistake reads as one diagnostic across the two halves, among it a comparison of vectors of two sizes, the uses of a local whose product the compiler refused, a value from an unknown function used in an operation, and a return of the wrong type, which the compiler reports on the return, where TypeScript does). For the shapes two passes both refused (proposal 0008), honest-refusals.test.ts (one mistake, one diagnostic, in compile() and in the editor): for…in and try, and a throw, an await, a yield, a template string and a spread with what each holds, in a body and at the top level; var in a body, at the top level and in a namespace, one that declares a parameter again and one of a list with no type; async and generator functions as a declaration, a value, a class’s method, a mixin’s and an object literal’s, a body no call lowers included, with a call of each and a local declared from one; a spread in a list in a local, a module constant or variable, a field, a static field, a default and an argument, and a spread argument; a rest element in a list assigned to; a type inside a namespace, and a parameter that names it; a generic interface or object-type alias, directly and through an alias, typing a parameter, a return, a local, a module constant or variable, a binding and an array of them, a field of a class or an interface, a method’s, a static function’s or a constructor’s signature, and an as; each pinned whole in compile() and in the editor’s merged list, TypeScript’s entries included, with a use of what it declares, and the multi-file path’s in compileTsSources. refused-names.ts keeps more reads quiet there: a name whose declaration names a type refused at its declaration, or a class or interface that holds one; a var read outside the block it is written in; a local declared from a call of a function or a method refused where it is written, through the class it is called on; N.x and N.M.x where what a namespace declares was refused; and C.K, a static field refused where it is written (staticFieldRefused). A class whose extends names a base refused where it is written, class D<T> extends B<T> with its type parameter, is that one TS8002: nothing more is said of the base it misses, of a new of it or of a read of what the base would have given it (src/compiler/ts/generic-classes.test.ts). mergeDiagnostics drops TypeScript’s report of what the compiler refused whole there (repeatsRefusal).

The files that verify it at commit 26de7be8, each at the first line that names the rule:

Explained in

The sections of the surface document that explain this rule, at commit 26de7be8:

Error codes that enforce it

The diagnostic codes the rule names under Enforced by, or whose registry text names the rule:

TS8002 UNKNOWN_TYPE
A type name nothing declares, said once for the file wherever it is written (a parameter, a claim, a type argument, B<vec3<Foo>> included, an alias, an implements clause, the base a class or an interface extends, a body no call lowers), a type the library declares for TypeScript alone (Number) where the file declares none of its name, or a type this surface does not take in a position the mapper reads (Rule 2.1).
TS8022 UNKNOWN_NAME
Reference to a name TypeShade cannot resolve (identifier, struct field, or struct shape) that is not a function call (UNKNOWN_FN) or a type name (UNKNOWN_TYPE), in a body a call lowers or in one no call lowers; a name the library declares for TypeScript's own use (Object, Math, Symbol), or the file declares as an enum, a namespace, a class or a type, read as a value says what it is.
TS8072 IMPORT
An import the compiler does not follow (Rule 3.9, surface §68, proposals 0022 and 0024): a path that names no file or one this compile cannot read, a file that is not a shader module, a package no node_modules holds, a subpath a package's exports does not name, a package's name alone when it has no exports, a # specifier or one that is neither relative nor a package name, a name the module does not export, and the forms a shader module has no use for (a default import or export, an import that names nothing, import(...), require, a module namespace used as a value).

See also

Source

The rule at commit 26de7be8:

Edit this page Report a problem