Skip to main content

How TypeScript Compiler DOes Type Checking

The compiler starts by parsing the TypeScript source code(.tsfiles) into an Abstract Syntax Tree (AST).

Type Checking

The Type Checking phase is a crucial part of the TypeScript compilation process, as it helps catch type-related errors early in the development process. During this phase, the TypeScript compiler analyzes the type information in the Abstract Syntax Tree (AST) and checks if the types are being used correctly according to the language rules. Here are the key processes involved in the Type Checking phase:

  1. Type Inference: TypeScript automatically infers the types of variables and expressions when they're not explicitly specified by the developer. Type inference is based on the values assigned to variables, function return types, and contextual typing (e.g., when using callback functions). The TypeScript compiler uses these inferred types during type checking.

  2. Type Annotations: TypeScript allows developers to explicitly specify types using type annotations. These annotations provide additional information to the TypeScript compiler, helping it better understand the developer's intent and catch type-related errors. Type annotations can be added to variables, function parameters, and function return types.

  3. Type Compatibility: The TypeScript compiler checks whether one type is compatible with another, based on the structural compatibility of the types. This process is involved in various scenarios, such as when assigning a value to a variable or passing an argument to a function. The TypeScript compiler analyzes the properties and methods of the types and checks whether they are compatible according to the language rules.

  4. Type Guards: TypeScript supports type guards, which are expressions that help narrow down the types within a specific scope. Some common type guards include typeof, instanceof, and user-defined type guards using type predicates. Type guards are used during the type checking process to refine the type information and perform more accurate type checks.

  5. Type Aliases and Mapped Types: TypeScript provides mechanisms for creating new types by combining or transforming existing ones, such as type aliases and mapped types. Type aliases allow developers to create new names for existing types, while mapped types enable creating new types by iterating over properties of existing types. The TypeScript compiler takes these type constructs into account during type checking.

  6. Generics: Generics enable developers to write reusable, type-safe code by specifying type variables that can be instantiated with specific types later. Generics can be used with functions, classes, and interfaces. During the type checking phase, the TypeScript compiler checks how generics are used and whether they satisfy the constraints and type compatibility rules.

  7. Type Declaration Files: TypeScript uses type declaration files (.d.ts) to provide type information for external libraries or modules. These files help the TypeScript compiler understand the types and APIs of external code during the type checking phase, ensuring that the developer is using the library correctly.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.

SEE COURSE DETAILS

Type Inference In Detail

Type Inference is the process by which TypeScript automatically determines the type of a variable, expression, or function return value when it's not explicitly specified by the developer. TypeScript's type inference mechanism helps catch type-related errors and improves code readability by reducing the need for explicit type annotations in many cases. Here are the key steps involved in TypeScript's type inference process:

Let's see this diagram which porays the type inference process in TypeScript

  1. Variable Initialization: When a variable is initialized with a value, TypeScript infers the type of the variable based on the type of the value. For example, if a variable is initialized with a number, TypeScript infers the variable's type as number.

    let age = 30;
    // TypeScript infers the type of age as number
  2. Function Return Types: TypeScript infers the return type of a function based on the type of the value returned by the function. If a function has multiple return statements, TypeScript infers the return type as the union of the types of all the returned values.

    function sum(a: number, b: number) {
    return a + b;
    // TypeScript infers the return type as number
    }
  3. Contextual Typing: TypeScript uses the context in which a variable or expression is used to infer its type. Contextual typing is particularly useful when dealing with callback functions, as it can infer the types of the callback function's parameters based on the expected types in the calling function.

    const numbers = [1, 2, 3, 4, 5];
    numbers.map((num) => num * 2);
    // TypeScript infers the type of num as number
  4. Best Common Type: When TypeScript needs to infer the type of an array or a tuple, it looks for the best common type that can accommodate all the elements. The best common type is determined by analyzing the types of the elements and finding a compatible type that satisfies all of them.

    const mixedArray = [1, "hello", true];
    // TypeScript infers the type as (string | number | boolean)[]
  5. Type Widening: TypeScript sometimes widens the inferred type to a more general type to account for future assignments or modifications to the variable. For example, when inferring the type of a variable initialized with null or undefined, TypeScript might widen the type to any or unknown.

    let data = null;
    // TypeScript infers the type as any
  6. Control Flow Analysis: TypeScript uses control flow analysis to narrow down the types of variables within specific branches of the code. It tracks how the type of a variable changes across different control flow constructs, such as if, else, for, and while statements.

    function process(input: string | number) {
    if (typeof input === "string") {
    // TypeScript infers the type of input as string within this block
    } else {
    // TypeScript infers the type of input as number within this block
    }
    }

TypeScript's type inference mechanism involves variable initialization, function return types, contextual typing, best common type, type widening, and control flow analysis to automatically deduce the types of variables, expressions, and function return values.

What Can You Do Next 🙏😊

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.

YouTube @cloudaffle