The type checker is the semantic analysis core of the TypeScript compiler. It consumes the AST produced by the parser and the symbol table built by the binder, then performs symbol resolution, type inference, type compatibility checking, and generates all semantic diagnostics. The type checker is implemented in src/compiler/checker.ts, which is by far the largest file in the repository (~70,000 lines).
For parser and AST details, see 2.1 For binder and symbol table construction, see 2.2 For how Program manages the checker lifecycle, see 2.5 For the public-facing TypeScript compiler API, see 7
The checker is created lazily by Program.getTypeChecker() via createTypeChecker in src/compiler/program.ts. It wraps all bound source files from the program and performs semantic analysis on demand.
Compilation Pipeline — Code Entity Mapping
Sources: src/compiler/program.ts50 src/compiler/checker.ts1-1151 src/compiler/emitter.ts1-426
createTypeCheckercreateTypeChecker(host: TypeCheckerHost): TypeChecker is the sole export from src/compiler/checker.ts that external consumers use. It returns an object implementing:
TypeChecker — the public interface defined in src/compiler/types.ts, consumed by the language service and public API.EmitResolver — an internal interface consumed by the emitter and declaration emitter to answer questions about symbol visibility, constant values, and emit-relevant type information.The factory closes over all internal state: relation maps, type and symbol caches, diagnostic arrays, and configuration derived from CompilerOptions.
Sources: src/compiler/checker.ts1-1151 src/compiler/program.ts50
Type Interface and TypeFlagsEvery type in the TypeScript type system is represented by the Type interface in src/compiler/types.ts. The flags: TypeFlags bitmask field identifies the exact variety of each type instance. The checker creates typed objects that implement Type subinterfaces (LiteralType, UnionType, IntersectionType, ObjectType, TypeParameter, etc.).
Type Hierarchy via TypeFlags
Key TypeFlags groupings:
| Group | Members |
|---|---|
Nullable | Undefined | Null |
StringLike | String | StringLiteral | TemplateLiteral | StringMapping |
NumberLike | Number | NumberLiteral | Enum |
StructuredType | Object | Union | Intersection |
Instantiable | TypeParameter | Index | IndexedAccess | Conditional | Substitution | TemplateLiteral | StringMapping |
StructuredOrInstantiable | StructuredType | Instantiable |
Narrowable | Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive |
Sources: src/compiler/types.ts1-20 src/compiler/checker.ts459-1150
ObjectFlagsObject types (TypeFlags.Object) carry a second bitmask, objectFlags: ObjectFlags, that further classifies them. Key values:
| Flag | Meaning |
|---|---|
Class | Created by a class declaration |
Interface | Created by an interface declaration |
Reference | Instantiation of a generic type (e.g. Array<string>) |
Tuple | Tuple type |
Anonymous | Object literal type or function type |
Mapped | Mapped type |
Instantiated | Instantiation of a generic object type |
ObjectLiteral | Fresh object literal type |
EvolvingArray | Narrowing-evolved array type |
ReverseMapped | Created by reverse-mapped type inference |
Sources: src/compiler/types.ts1-20 src/compiler/checker.ts930-940
Symbol and SymbolFlagsSymbol objects are created by the binder and decorated by the checker. The flags: SymbolFlags bitmask identifies what kind of entity a symbol represents.
| Flag Category | Members |
|---|---|
| Value declarations | FunctionScopedVariable, BlockScopedVariable, Property, EnumMember, Function, Class, Enum, ValueModule, GetAccessor, SetAccessor, Method, Constructor |
| Type declarations | Interface, TypeAlias, TypeParameter, TypeLiteral |
| Namespace | NamespaceModule, ValueModule |
| Alias | Alias (imports, re-exports) |
| Transient | Transient (checker-synthesized, e.g. mapped type members) |
The checker also uses CheckFlags on TransientSymbol to encode additional metadata such as Readonly, Optional, HasNonUniformType, Instantiated, ReverseMapped, and Mapped.
Sources: src/compiler/types.ts1-20 src/compiler/checker.ts256-262
SignatureFunction, method, and constructor overloads are represented by Signature objects. Each Signature holds:
typeParameters: generic type parametersparameters: Symbol[]SignatureFlags bits (e.g. HasRestParameter, HasLiteralTypes, Abstract, IsInnerCallChain)declaration: the originating AST nodeSources: src/compiler/types.ts1-20 src/compiler/checker.ts1017-1021
The checker avoids redundant computation by associating cached data with nodes and symbols:
NodeLinks (in src/compiler/types.ts) — attached to AST nodes via a node id. Stores: resolved type (resolvedType), resolved signature, inferred return type, contextual type, flags like NodeCheckFlags (e.g. SuperInstance, ConstructorReference, CapturedBlockScopedBinding).SymbolLinks (in src/compiler/types.ts) — attached to Symbol objects. Stores: declared type, resolved type, type parameters, inferred type, aliased symbol, export maps, and more.NodeCheckFlags (on NodeLinks) encodes semantic properties discovered during checking, such as whether a super call is needed, whether a binding is captured across a closure boundary, or whether a constructor requires type checking of the base class.
Sources: src/compiler/types.ts1-20 src/compiler/checker.ts916-920
checkSourceFileWhen the program requests semantic diagnostics, the checker calls an internal checkSourceFile for each source file. This walks the top-level statements and triggers recursive checking. Diagnostics are deferred until this point; the checker is otherwise lazy.
getTypeOfExpression and CheckModeThe central internal function for deriving a type from an expression node is getTypeOfExpression. It delegates to checkExpression, which dispatches based on the expression's SyntaxKind. The CheckMode const enum controls how the check proceeds:
CheckMode | Description |
|---|---|
Normal | Standard type checking |
Contextual | Deriving a contextual type from a parent expression |
Inferential | Type inference from an argument against a parameter type |
SkipContextSensitive | Skip context-sensitive subexpressions (arrow functions, object literals) |
SkipGenericFunctions | Skip generic functions during overload resolution |
IsForSignatureHelp | Invocation from the signature help service |
RestBindingElement | Checking a rest binding element |
TypeOnly | Type-only context |
Expression Type Resolution Flow
Sources: src/compiler/checker.ts1157-1259 src/compiler/types.ts453-456
InferenceContext and InferencePriorityWhen the checker resolves a generic call expression, it creates an InferenceContext containing one InferenceInfo per type parameter. The inferTypes function walks the relationship between the argument type and the parameter type, collecting candidates.
InferencePriority ranks candidates. Higher-priority inferences override lower ones:
| Priority | Meaning |
|---|---|
NakedTypeVariable | Direct inference against a type parameter |
SpeculativeTuple | Speculation for tuple rest types |
SubstituteSource | Source of a substitution type |
HomomorphicMappedType | From homomorphic mapped type |
PartialHomomorphicMappedType | Partial homomorphic |
MappedTypeConstraint | From mapped type constraint |
ContravariantConditional | Contravariant conditional |
ReturnType | From return type |
LiteralKeyof | Literal keyof inference |
NoConstraints | Without constraint application |
AlwaysStrict | Strict inference mode |
MaxValue | Sentinel |
InferenceFlags on the context indicate whether return types should be fixed, whether inference is for a homomorphic mapped type, etc.
Sources: src/compiler/types.ts453-456 src/compiler/checker.ts453-456
The checker maintains several Map<string, RelationComparisonResult> objects that cache the result of comparing two types. These are the key relations:
| Relation | Use |
|---|---|
assignableRelation | Is type S assignable to type T? (most common check) |
strictSubtypeRelation | Is S a strict subtype of T? |
comparableRelation | Is S comparable to T? (for switch, ==, etc.) |
identityRelation | Are S and T identical? |
enumRelation | Enum assignability |
Cache keys are formed from the pair of type IDs (TypeId). Cached values are RelationComparisonResult bitmask values.
Assignability Checking Flow
TernaryThe internal Ternary enum drives recursive type compatibility checks. It handles circular type references by allowing a Maybe result that can later be resolved:
| Value | Meaning |
|---|---|
False = 0 | Types are not related |
Unknown = 1 | Relationship unknown (circuit breaker) |
Maybe = 3 | Provisionally related (used for recursive types) |
True = -1 | Types are related |
IntersectionStateWhen checking assignability involving intersection types, IntersectionState tracks context to avoid redundant checks:
| Value | Meaning |
|---|---|
None = 0 | Not inside an intersection check |
Source = 1 << 0 | Currently distributing over source intersection |
Target = 1 << 1 | Currently distributing over target intersection |
Sources: src/compiler/types.ts1-20 src/compiler/checker.ts467
Symbol resolution maps AST name references to Symbol objects. The main internal entry points are:
resolveEntityName — resolves a qualified name or identifier in type position.resolveSymbol — follows alias chains to find the final resolved symbol.resolveName — resolves a name in a given scope by walking the scope chain.Symbol Resolution Process
Sources: src/compiler/checker.ts125-126 src/compiler/types.ts1-20
The checker uses the flow graph built by the binder to compute narrowed types for variables at specific AST locations. The key entry point is getFlowTypeOfReference.
TypeFactsThe TypeFacts const enum (marked @internal and exported from src/compiler/checker.ts) is a bitmask describing which type guards can narrow a given type. Each bit represents a predicate that is applicable to some set of values.
Key TypeFacts groupings:
| Group | Meaning |
|---|---|
TypeofEQString, …TypeofEQFunction | typeof x === "string" etc. |
TypeofNEString, …TypeofNEFunction | typeof x !== "string" etc. |
EQUndefined, EQNull, EQUndefinedOrNull | x === undefined/null |
NEUndefined, NENull, NEUndefinedOrNull | x !== undefined/null |
Truthy, Falsy | Truthiness guards |
IsUndefined, IsNull | Type contains undefined/null |
All | Full set of applicable facts |
Composite facts like StringStrictFacts, NumberFacts, ObjectFacts are pre-computed combinations. The checker calls getTypeFacts(type) to determine which facts apply to a type, then intersects facts with the current flow condition to determine the narrowed type.
Sources: src/compiler/checker.ts1229-1259
For a variable reference inside a conditional, the checker:
FlowNode backward.FlowCondition node, applies narrowing via narrowType (using TypeFacts and user-defined type predicates).FlowAssignment nodes, uses the assigned type.FlowLabel (join points for union), combines the narrowed types from each incoming branch.The result is a FlowType — either a regular Type or an IncompleteType when the analysis is still in progress (for cyclic flows).
Sources: src/compiler/checker.ts215-225 src/compiler/types.ts1-20
| Enum | Location | Purpose |
|---|---|---|
TypeFacts | checker.ts | Narrowing predicates for flow analysis |
CheckMode | checker.ts | Controls behavior of checkExpression |
IntersectionState | checker.ts | Tracks position in intersection compatibility check |
WideningKind | checker.ts | Controls widening behavior for function returns vs. normals |
IterationUse | checker.ts | Distinguishes for-of, yield*, spread, destructuring |
IterationTypeKind | checker.ts | Yield, Return, or Next type of an iterator |
Ternary | types.ts | Result of recursive type compatibility check |
RelationComparisonResult | types.ts | Cached result of a relation check |
InferenceFlags | types.ts | Metadata on InferenceContext |
InferencePriority | types.ts | Priority ordering for type inference candidates |
ContextFlags | types.ts | Flags on the type-checking context (e.g. InConditionalType) |
ObjectFlags | types.ts | Sub-classification of TypeFlags.Object |
SymbolFlags | types.ts | What kind of entity a symbol represents |
CheckFlags | types.ts | Additional flags on TransientSymbol |
SignatureFlags | types.ts | Properties of a Signature |
TypeFormatFlags | types.ts | Controls output of typeToString |
NodeBuilderFlags | types.ts | Controls type-to-node conversion in the type node builder |
Sources: src/compiler/checker.ts1157-1259 src/compiler/types.ts1-20
EmitResolver InterfaceThe emitter and declaration emitter do not call TypeChecker methods directly for emit-time decisions. Instead, the checker creates an EmitResolver object (defined in src/compiler/types.ts) that answers a narrower set of questions needed during emit:
isReferencedAliasDeclaration(node) — should an import alias be emitted?isValueAliasDeclaration(node) — does an alias refer to a value?isImplementationOfOverload(node) — is this the implementation signature?getConstantValue(node) — compile-time constant value of an enum member access.getReferencedDeclarationWithCollidingName(node) — collision detection.isDeclarationVisible(node) — for declaration emit: is a declaration externally visible?collectLinkedAliases(node) — aliases that must be emitted together.These are all computed by the same internal checker state but presented through a restricted interface.
Sources: src/compiler/types.ts1-20 src/compiler/emitter.ts71-73
TypeChecker InterfaceThe TypeChecker interface (in src/compiler/types.ts, reflected in tests/baselines/reference/api/typescript.d.ts) is what the language service and external consumers use. Its methods fall into these categories:
Type Query Methods
| Method | Description |
|---|---|
getTypeAtLocation(node) | Type of an expression or declaration node |
getTypeOfSymbolAtLocation(symbol, node) | Type of a symbol in a given expression context |
getTypeFromTypeNode(node) | Type represented by a type-syntax node |
getContextualType(node) | Contextual (expected) type at an expression position |
getReturnTypeOfSignature(sig) | Return type of a Signature |
getBaseTypes(type) | Base types of a class or interface |
getNonNullableType(type) | Strip null and undefined |
Symbol Query Methods
| Method | Description |
|---|---|
getSymbolAtLocation(node) | Symbol referenced by a node |
getSymbolsInScope(location, meaning) | Symbols visible at a location (by SymbolFlags) |
getExportsOfModule(symbol) | Exports of a module symbol |
getPropertiesOfType(type) | Property symbols of a type |
getPropertyOfType(type, name) | Single named property |
getIndexInfosOfType(type) | Index signatures |
getSignaturesOfType(type, kind) | Call or construct signatures |
Signature and Overload Methods
| Method | Description |
|---|---|
getResolvedSignature(call) | Resolved Signature for a call expression |
getSignatureFromDeclaration(decl) | Signature for a function-like declaration |
Display and Serialization
| Method | Description |
|---|---|
typeToString(type) | Human-readable type string |
symbolToString(symbol) | Human-readable symbol string |
signatureToString(sig) | Human-readable signature string |
getFullyQualifiedName(symbol) | Dotted qualified name |
Diagnostics
| Method | Description |
|---|---|
getSemanticDiagnostics(sourceFile?) | All semantic diagnostics, optionally scoped to a file |
Predicate Methods
| Method | Description |
|---|---|
isAssignableTo(source, target) | Assignability check (public) |
isImplementationOfOverload(node) | Whether a function is the implementation of an overload |
isOptionalParameter(node) | Whether a parameter is optional |
Sources: tests/baselines/reference/api/typescript.d.ts1-200 src/compiler/types.ts1-20
Type Checker Internal Relationships
Sources: src/compiler/checker.ts1-1259 src/compiler/types.ts1-20 src/compiler/program.ts50
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.