microsoft/TypeScript
Diagnostics
How a single user-visible compiler error or warning is defined, raised, formatted, and surfaced.
Source
| File | Role |
|---|---|
src/compiler/diagnosticMessages.json |
Master list of every diagnostic message (~2,130 entries, 8,559 lines) |
src/compiler/diagnosticInformationMap.generated.ts |
Generated lookup map (created by hereby generate-diagnostics) |
scripts/processDiagnosticMessages.mjs |
The generator |
src/compiler/programDiagnostics.ts |
Program-level diagnostic stream + dedup |
src/compiler/utilities.ts |
createDiagnosticForNode, chainDiagnosticMessages, formatting helpers |
src/compiler/types.ts |
Diagnostic, DiagnosticMessage, DiagnosticCategory, DiagnosticMessageChain types |
Purpose
Diagnostics are the compiler's user-facing output. They have to be:
- Localisable. The English message lives in
diagnosticMessages.json; translations live insrc/loc/lcl/<locale>/diagnosticMessages.generated.json.lcl. The--localeflag and the editor's language pick the right translation. - Stable. Each entry has a numeric
code(e.g.,2304: "Cannot find name '{0}'.") that scripts and editors rely on. New entries get new codes; existing codes don't change meaning. - Categorised. Each is
Error,Warning,Suggestion, orMessage. Suggestions only surface in the language service. - Locatable. Each
Diagnosticcarries a source file, position, and length so editors can underline the relevant code. - Chainable. A single error often has nested context ("Type X is not assignable to type Y" → "Property 'foo' is missing").
DiagnosticMessageChainrepresents the cascade.
How it works
graph LR
Json["diagnosticMessages.json"] -->|hereby generate-diagnostics| Gen["diagnosticInformationMap.generated.ts"]
Gen --> Code["Code references Diagnostics.X"]
Code --> Create["createDiagnosticForNode / error()"]
Create --> Stream["Diagnostic stream on Program / SourceFile"]
Stream --> Format["formatDiagnostic / formatDiagnosticsWithColorAndContext"]
Format --> Out["stderr (tsc) / language service / IDE"]Defining a new diagnostic
Add an entry to
diagnosticMessages.json:"Property '{0}' does not exist on type '{1}'.": { "category": "Error", "code": 2339 }Run
hereby generate-diagnostics. This regeneratesdiagnosticInformationMap.generated.tswith aDiagnostics.Property_0_does_not_exist_on_type_1constant.Reference it in code:
error( node, Diagnostics.Property_0_does_not_exist_on_type_1, propName, typeStr );
The constant key is derived deterministically from the message — replacing punctuation with underscores and trimming. This is why diagnostic messages are stable strings, not just codes.
Formatting
tsc formats diagnostics for the terminal in two flavours:
formatDiagnostic(diagnostic, host)— single-line:path/to/file.ts(12,5): error TS2339: ....formatDiagnosticsWithColorAndContext(diagnostics, host)— colourful, multi-line, with source-context excerpts. Default when stdout is a TTY.
The language service returns diagnostics raw and lets the editor handle presentation.
Diagnostic chaining
A type error like:
Type '{ a: number; }' is not assignable to type '{ a: string; b: number; }'.
Types of property 'a' are incompatible.
Type 'number' is not assignable to type 'string'.is one root Diagnostic whose messageText is a DiagnosticMessageChain linked-list. The checker builds these chains as it descends into structural-comparison failures via chainDiagnosticMessages.
Related information
A Diagnostic can have relatedInformation: DiagnosticRelatedInformation[], each pointing to a different file/range. The checker uses this for "see also" hints — e.g., "the conflicting declaration is here" with a pointer to the other declaration.
Comment directives
// @ts-ignore, // @ts-expect-error, and // @ts-nocheck suppress diagnostics on the next line / whole file. The parser records these in SourceFile.commentDirectives. The diagnostic stream filters against the directive list at output time. @ts-expect-error reports a new diagnostic if the suppressed line was not actually erroring.
Diagnostic streams
A Program exposes several streams:
getOptionsDiagnostics()—tsconfig.jsonproblems, e.g., invalidtarget.getGlobalDiagnostics()— missing libs, lib conflicts.getSyntacticDiagnostics(sourceFile?)— parse errors.getSemanticDiagnostics(sourceFile?)— type errors.getDeclarationDiagnostics(sourceFile?)—--declarationsynthesis errors.getSuggestionDiagnostics(sourceFile)— language-service suggestions.
Each is computed lazily and memoised. The programDiagnostics.ts module dedups identical diagnostics that come from multiple sources.
Integration points
tscwrites formatted diagnostics to stderr and uses the count to set the exit code.tsserversends raw diagnostic objects insemanticDiag,syntaxDiag,suggestionDiagevents, throttled per-file.- Editors translate
Diagnostic.codeinto doc links (e.g.,https://typescript.tv/errors/#TS2304). - Code fixes in
src/services/codefixes/are registered against specific diagnostic codes.
Entry points for modification
- New diagnostic — edit
diagnosticMessages.json, runhereby generate-diagnostics, reference the new constant. - New formatting —
formatDiagnostic*inutilities.ts. - New comment directive — extend
commentDirectivesinscanner.tsandapplyCommentDirectivesinprogramDiagnostics.ts. - Per-locale translations live under
src/loc/lcl/and are managed by Microsoft's localisation team — generally not changed by contributors.
See primitives/diagnostic for the data shape.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.