Lesson 08-TypeScript Core Functionality Source Code Analysis

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
  }
}

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here

Share your love