Type Checking Source Code
Type Compatibility Checking Source Code Implementation
Core Type Compatibility Algorithm:
// Source Location: src/compiler/checker.ts
function isTypeAssignableTo(source: Type, target: Type, checker: TypeChecker): boolean {
// Direct comparison for basic types
if (source.flags & TypeFlags.Any || target.flags & TypeFlags.Any) {
return true
}
if (source.flags & TypeFlags.Never) {
return false
}
if (source === target) {
return true
}
// Object type compatibility check
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
return isObjectTypeAssignableTo(source as ObjectType, target as ObjectType, checker)
}
// Union type compatibility check
if (source.flags & TypeFlags.Union) {
return everyTypeInUnion(source, t => isTypeAssignableTo(t, target, checker))
}
// Intersection type compatibility check
if (source.flags & TypeFlags.Intersection) {
return someTypeInIntersection(source, t => isTypeAssignableTo(t, target, checker))
}
// Generic type compatibility check
if (source.flags & TypeFlags.Generic) {
return isGenericTypeAssignableTo(source as GenericType, target, checker)
}
return false
}
// Detailed object type compatibility check
function isObjectTypeAssignableTo(source: ObjectType, target: ObjectType, checker: TypeChecker): boolean {
// Check if all required properties exist in the source type
for (const [propName, targetProp] of target.members) {
const sourceProp = source.members.get(propName)
if (!sourceProp) {
if (!(targetProp.flags & SymbolFlags.Optional)) {
return false
}
continue
}
if (!isTypeAssignableTo(sourceProp.type, targetProp.type, checker)) {
return false
}
}
return true
}
Generic Type Checking Source Code Implementation
Generic Type Instantiation and Checking:
// Source Location: src/compiler/checker.ts
function checkGenericFunction(node: FunctionDeclaration, checker: TypeChecker) {
const typeParameters = node.typeParameters?.map(tp => checker.getTypeParameter(tp)) || []
const typeArguments = /* Obtain type arguments from call site or infer */ []
// Create instantiated generic type
const instantiatedType = instantiateGenericType(
getFunctionType(node, checker),
typeParameters,
typeArguments,
checker
)
// Check function body
checker.checkFunctionBody(node, instantiatedType)
}
// Generic type instantiation implementation
function instantiateGenericType(
genericType: GenericType,
typeParameters: TypeParameter[],
typeArguments: Type[],
checker: TypeChecker
): Type {
// Validate type argument count
if (typeParameters.length !== typeArguments.length) {
throw new Error('Type argument count mismatch')
}
// Create substitution mapping
const substitutionMap = new Map<TypeParameter, Type>()
for (let i = 0; i < typeParameters.length; i++) {
substitutionMap.set(typeParameters[i], typeArguments[i])
}
// Recursively substitute type parameters
return applyTypeSubstitution(genericType, substitutionMap, checker)
}
Union and Intersection Type Checking Source Code
Union Type Checking Implementation:
// Source Location: src/compiler/checker.ts
function isUnionTypeAssignableTo(source: UnionType, target: Type, checker: TypeChecker): boolean {
// Union type is assignable to target if all member types are assignable to target
return everyTypeInUnion(source, memberType =>
isTypeAssignableTo(memberType, target, checker)
)
}
// Union type narrowing implementation
function narrowUnionType(node: Expression, checker: TypeChecker): Type {
const unionType = checker.getTypeAtLocation(node) as UnionType
const narrowedTypes: Type[] = []
for (const memberType of unionType.types) {
if (canNarrowType(node, memberType, checker)) {
narrowedTypes.push(memberType)
}
}
if (narrowedTypes.length === 1) {
return narrowedTypes[0]
}
return unionType
}
Intersection Type Checking Implementation:
// Source Location: src/compiler/checker.ts
function isIntersectionTypeAssignableTo(source: IntersectionType, target: Type, checker: TypeChecker): boolean {
// Intersection type is assignable to target if at least one member type is assignable to target
return someTypeInIntersection(source, memberType =>
isTypeAssignableTo(memberType, target, checker)
)
}
// Intersection type application implementation
function applyIntersectionType(node: Expression, checker: TypeChecker): Type {
const intersectionType = checker.getTypeAtLocation(node) as IntersectionType
let resultType: Type = createNeverType()
for (const memberType of intersectionType.types) {
resultType = createIntersectionType(resultType, memberType, checker)
}
return resultType
}
Index and Mapped Type Checking Source Code
Index Type Access Checking:
// Source Location: src/compiler/checker.ts
function checkIndexAccess(node: ElementAccessExpression, checker: TypeChecker): Type {
const objectType = checker.getTypeAtLocation(node.expression)
const indexType = checker.getTypeAtLocation(node.argumentExpression)
// Check if index signature exists
if (objectType.flags & TypeFlags.Object) {
const objectTypeWithIndex = objectType as ObjectType
if (hasIndexSignature(objectTypeWithIndex)) {
const indexSignature = getIndexSignature(objectTypeWithIndex)
if (!isTypeAssignableTo(indexType, indexSignature.parameter.type, checker)) {
checker.error(node.argumentExpression, DiagnosticMessages.IndexSignatureMismatch)
}
return indexSignature.returnType
}
}
checker.error(node, DiagnosticMessages.NoIndexSignature)
return createAnyType()
}
Mapped Type Transformation Checking:
// Source Location: src/compiler/checker.ts
function transformMappedType(
node: MappedTypeNode,
checker: TypeChecker
): Type {
const sourceType = checker.getTypeAtLocation(node.typeParameter.constraint)
const modifierFlags = getModifierFlags(node)
const newMembers: SymbolTable = new Map()
// Iterate through all properties of the source type
for (const [propName, propSymbol] of sourceType.members) {
// Check if mapping condition is satisfied (e.g., keyof T)
if (satisfiesMappingCondition(propName, node, checker)) {
// Apply modifier transformations
const newFlags = applyModifiers(propSymbol.flags, modifierFlags)
// Create new property type
const newType = transformType(propSymbol.type, node.type, checker)
newMembers.set(propName, {
flags: newFlags,
type: newType
})
}
}
return createObjectType(newMembers)
}
Conditional Type Checking Source Code
Conditional Type Resolution Implementation:
// Source Location: src/compiler/checker.ts
function checkConditionalType(
node: ConditionalTypeNode,
checker: TypeChecker
): Type {
const checkType = checker.getTypeAtLocation(node.checkType)
const extendsType = checker.getTypeAtLocation(node.extendsType)
// Check if condition holds
if (isTypeAssignableTo(checkType, extendsType, checker)) {
return checker.getTypeAtLocation(node.trueType)
} else {
return checker.getTypeAtLocation(node.falseType)
}
}
// Conditional type inference implementation
function inferConditionalType(
node: ConditionalTypeNode,
checker: TypeChecker
): InferenceResult {
const checkType = checker.getTypeAtLocation(node.checkType)
const extendsType = checker.getTypeAtLocation(node.extendsType)
// Attempt to infer type variables in checkType
const inferredTypes = tryInferTypes(checkType, extendsType, checker)
if (inferredTypes) {
// Check condition with inferred types
const substitutedCheckType = substituteTypes(checkType, inferredTypes)
if (isTypeAssignableTo(substitutedCheckType, extendsType, checker)) {
return {
isInferred: true,
type: checker.getTypeAtLocation(node.trueType),
inferredTypes
}
}
}
return {
isInferred: false,
type: checker.getTypeAtLocation(node.falseType),
inferredTypes: undefined
}
}



