microsoft/TypeScript
Type
The checker's view of a value. Types are independent of any one declaration — they describe the shape a value can have. The whole "TypeScript is a type system on JavaScript" story bottoms out at the Type interface.
Definition
export interface Type {
flags: TypeFlags;
/* @internal */ id: TypeId;
symbol: Symbol;
pattern?: DestructuringPattern;
aliasSymbol?: Symbol;
aliasTypeArguments?: readonly Type[];
/* @internal */ aliasTypeArgumentsContainsMarker?: boolean;
/* @internal */ permissiveInstantiation?: Type;
/* @internal */ restrictiveInstantiation?: Type;
/* @internal */ uniqueLiteralFilledInstantiation?: Type;
/* @internal */ immediateBaseConstraint?: Type;
/* @internal */ widened?: Type;
}TypeFlags distinguishes the kind:
- Primitives:
Any,Unknown,String,Number,BigInt,Boolean,EnumLiteral,StringLiteral,NumberLiteral,BooleanLiteral,BigIntLiteral,Symbol,UniqueESSymbol,Void,Undefined,Null,Never. - Compound:
Object,Union,Intersection,Index,IndexedAccess,Conditional,Substitution,TemplateLiteral,StringMapping. - Markers:
TypeParameter,Literal,Nullable,Singleton,Instantiable,StructuredOrInstantiable,Narrowable,IncludesMissingType.
Subtypes carry their own properties: ObjectType adds members and signatures; UnionType lists alternatives; ConditionalType carries checkType/extendsType/trueType/falseType; etc.
Construction
Types are not allocated directly. Always go through the checker's factories: getStringType(), getNumberLiteralType(value), getUnionType(types), createAnonymousType(symbol, members, signatures, ...), etc.
The checker flyweights structural types: two unions of the same alternatives produce the same Type instance, so equality is reference equality. This is what makes the assignability cache work.
Type flags vs. object flags
For Object types, an additional objectFlags: ObjectFlags field distinguishes:
Class,Interface— declared types.Reference— instantiation of a generic type.Tuple,Anonymous— structural types.Mapped,EvolvingArray,JsxAttributes.- Internal markers like
JSLiteral,FreshLiteral,ObjectLiteralPatternWithComputedProperties.
Resolved members
ResolvedType (a subtype of ObjectType) is what callers iterate over when asking "what are the members of this type?". It exposes:
members: SymbolTableproperties: Symbol[]callSignatures: readonly Signature[]constructSignatures: readonly Signature[]indexInfos: readonly IndexInfo[]
getResolvedMembers(type) is the lazy on-demand resolver. The checker calls it the first time members of a type are asked for and caches the result on the type instance.
Type relationships
The checker's most-used algorithms operate on type pairs:
isTypeAssignableTo(source, target)— issourcea subtype oftarget?isTypeRelatedTo(source, target, relation)— generalisation;relationis one ofassignableRelation,subtypeRelation,comparableRelation,identityRelation,enumRelation.compareTypesIdentical(a, b)— strict identity check.
These descend through structural shape, recording which subtype/equality assumptions are active to handle recursion. The resulting "relation" maps are cached per checker instance so the same pair is never compared twice.
Generics
A TypeParameter is Type & { isThisType?: boolean; constraint?: Type; default?: Type; symbol: Symbol; ... }. Generic types are uninstantiated; the checker substitutes type parameters for concrete types via instantiateType(type, mapper).
A TypeReference (a kind of ObjectType) represents an instantiation: Array<string> is a TypeReference with target = Array and typeArguments = [string]. The reference's resolved members are computed lazily by substituting T → string into Array's declared members.
Conditional types
ConditionalType is one of the more involved kinds. It carries:
checkType: Type— what's on the left ofextends.extendsType: Type— what's on the right.resolvedTrueType: Type— the branch when assignable.resolvedFalseType: Type— the branch when not.inferTypeParameters?: TypeParameter[]—infer Xplaceholders.
When the checker instantiates a conditional type with concrete arguments, it tries the extends relation. If decidable, it picks one branch; if not, the conditional remains unresolved (a deferred conditional) until more is known.
Narrowing
Within a block, the same symbol can have different types at different positions: if (typeof x === "string") { x.toUpperCase(); }. The checker computes a flow type for each reference using the binder's flow graph. The flow walker calls into narrowType* helpers for each kind of guard (typeof, instanceof, equality, in, custom type predicates).
Widening / freshness
Object literals and array literals start out fresh — their type allows extra checks to flag obvious typos. When assigned to a variable without an explicit type, they're widened into a regular type. The widened field on Type caches the result.
Integration points
- The checker is the only producer of
Type. - Callers include the language service (hover, completions, signature help), declaration emit (synthesising
.d.tstypes), and the emitter (asking for resolved imports and resolved external modules viaEmitResolver). - Some callers (refactors, code fixes) ask the checker for names of types via
typeToStringor for node representations vianodeBuilder.typeToTypeNode.
See also
- systems/checker — the producer.
- primitives/symbol — symbols and types are tightly linked but distinct.
- primitives/signature — the function-type-specific concept.
- features/declaration-emit — for type→syntax conversion.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.