This document covers the template type checking system in the Angular compiler (ngtsc), which validates Angular component templates for type errors by generating Type Check Blocks (TCBs) that are processed by the TypeScript compiler. This system ensures that template expressions, bindings, and references are type-safe according to the component's TypeScript class and the directives/pipes in scope.
For information about the overall compilation pipeline that feeds into template type checking, see 4.1 Angular Compiler Architecture and Decorator Processing For the template IR and transformation pipeline, see 4.2 Template Compilation Pipeline
The template type checking system transforms Angular templates into executable TypeScript code that can be validated by the TypeScript compiler. When the compiler encounters a component template, it generates a Type Check Block (TCB) — a TypeScript function that mirrors the template's structure and bindings. The TypeScript compiler then type-checks this generated code, and any diagnostics are mapped back to the original template locations using source mappings.
Template Type Checking Flow
Sources: packages/compiler-cli/src/ngtsc/typecheck/src/context.ts13-25 packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts9-38
A Type Check Block is a TypeScript function declaration generated for each component. The function typically has a parameter representing the component instance (this) and contains statements that mirror template constructs. The TCB validates:
$event types@if, @for, @switch, etc.)TCB Function Structure
| Component | Generated TCB Element | Purpose |
|---|---|---|
{{ hello }} | Expression statement | Type-check interpolation packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts31 |
[input]="value" | Property assignment | Validate input binding types packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts153 |
(animate.leave) | Function call | Check animation callback signature packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts34-40 |
a ?? b | Nullish coalescing | Handle nullish coalescing operators packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts85-93 |
typeof a | Typeof expression | Handle unary type operators packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts95-101 |
@let declaration | Variable declaration | Type-check local template variables packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts29 |
Sources: packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts30-182 packages/compiler-cli/src/ngtsc/typecheck/src/context.ts53-55
The TypeCheckContextImpl orchestrates TCB creation. It manages the lifecycle of shim files and handles inlining requirements when component classes are not exported or have other visibility constraints.
Key Classes and Their Roles
TypeCheckContextImpl: Central coordinator for a type-checking pass, managing multiple files and their associated shim data packages/compiler-cli/src/ngtsc/typecheck/src/context.ts201-212TypeCheckFile: Represents a single shim file (.ngtypecheck.ts) that contains generated TCBs for components in a specific source file packages/compiler-cli/src/ngtsc/typecheck/src/context.ts149OutOfBandDiagnosticRecorderImpl: Records errors that TypeScript cannot detect natively, such as missing pipes or invalid reference targets packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts47-48RegistryDomSchemaChecker: Validates that elements and attributes used in the template exist according to the provided schema packages/compiler-cli/src/ngtsc/typecheck/src/context.ts48Sources: packages/compiler-cli/src/ngtsc/typecheck/src/context.ts201-220 packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts47-80
Directives and components require special handling for type checking their inputs and outputs. The system distinguishes between generic and non-generic directives and uses different strategies accordingly.
Directive Type Checking Strategies
Input Binding Type Checking For each input binding, the system resolves the directive instance and validates the assignment. This includes handling:
Field or Signal type packages/compiler-cli/test/ngtsc/signal_forms_spec.ts33-53transform functions, which might change the expected type in the template packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts151-154Sources: packages/compiler-cli/src/ngtsc/typecheck/api/api.ts28-40 packages/compiler-cli/test/ngtsc/signal_forms_spec.ts109-131
Some template errors cannot be represented as TypeScript type errors in the TCB. These are collected by the OutOfBandDiagnosticRecorderImpl packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts47
Common OOB Diagnostics
ErrorCode.MISSING_PIPE (8004) when a pipe name is not found in the component's scope. It can also provide suggestions for standard Angular pipes packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts99-140ErrorCode.MISSING_REFERENCE_TARGET (8003) when #ref="target" refers to an exportAs name that does not exist packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts82-97ErrorCode.DEFERRED_PIPE_USED_EAGERLY (8012) and DEFERRED_DIRECTIVE_USED_EAGERLY (8013) when dependencies imported via deferredImports are used outside of a @defer block packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts142-200Extended diagnostics are optional checks that analyze the template AST for common pitfalls.
ErrorCode.INVALID_BANANA_IN_BOX (8101) detects ([prop])="val" instead of [(prop)]="val" packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts20ErrorCode.NULLISH_COALESCING_NOT_NULLABLE (8102) warns when ?? is used on an expression that is never null or undefined.Sources: packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts82-211 packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts12-230
The ErrorCode enum packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts12 defines the unique identifiers for Angular-specific diagnostics. These codes are used to categorize errors and link them to documentation.
| Code | Name | Description |
|---|---|---|
| 1054 | DUPLICATE_BINDING_NAME | Multiple inputs/outputs share the same binding name packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts58 |
| 2010 | COMPONENT_NOT_STANDALONE | Component has imports but is not marked as standalone: true packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts99-101 |
| 8003 | MISSING_REFERENCE_TARGET | No directive found with the specified exportAs name packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts93 |
| 8112 | UNUSED_LET_DECLARATION | An @let declaration is defined but never used in the template goldens/public-api/compiler-cli/error_code.api.md136 |
Sources: packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts12-230 goldens/public-api/compiler-cli/error_code.api.md8-144
The TypeCheckingConfig packages/compiler-cli/src/ngtsc/typecheck/api/api.ts37 interface controls the strictness of the type checker.
| Option | Description |
|---|---|
strictTemplates | Master switch for all strict template type checking packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts32 |
strictInputTypes | Whether to check the type of input bindings packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts121 |
strictAttributeTypes | Whether to check the type of static attributes packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts122 |
strictOutputEventTypes | Whether to check the type of $event in event bindings packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts203 |
Sources: packages/compiler-cli/src/ngtsc/typecheck/api/api.ts1-100 packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts119-123