Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 2

Typing in TypeScript, Python, and C#: A Comparative Guide

Recommended resources

Introduction

In our last lesson, we explored the concept of programming paradigms, which gave us a mental model for how different languages structure code and solve problems. You saw how your experience with Object-Oriented Programming in Angular contrasts with functional or imperative approaches, even within the same language like TypeScript. This lesson adds another crucial layer to your language-agnostic toolkit: the type system.

Understanding a language's type system is fundamental to writing correct, maintainable, and efficient code. It directly addresses your goal of understanding why you can pick up a new language easily—because concepts like typing are more important than syntax. Today, we will distinguish between two key axes of typing: static vs. dynamic and strong vs. weak. By the end, you'll be able to place TypeScript, Python, and C# on a comparative map, giving you a powerful framework for predicting a language's behavior.


Static vs. Dynamic Typing: The "When" of Type Checking

The first and most fundamental distinction in type systems is about when type errors are caught. Does the system check your code for type correctness before you run it, or does it wait until the program is actually executing?

To get a clear grasp of this concept and its practical implications, let's turn to a well-structured guide.

Static vs. Dynamic Typing: A Guide for App Leaders

This article provides an excellent, business-oriented breakdown of why typing matters. We'll focus on its clear, concise definitions.

Start by reading the section Static vs Dynamic Typing A Simple Explanation. The blueprint analogy for static typing is particularly useful. Then read the part describing dynamic typing, which uses the "building as you go" analogy. After grasping the core ideas, study the table in the section A quick side by side view. This table neatly summarizes the trade-offs, which are key to understanding why a project might choose one language over another.

As you just read, the difference is timing:

  • Static Typing: Type checks happen before the program runs, usually during a compilation or analysis step. Languages like TypeScript, C#, and Java are statically typed. This is like having an architect review a blueprint for structural flaws before any concrete is poured. You've seen this in action every time the TypeScript compiler or your IDE warns you about a type mismatch before you even open the browser.

  • Dynamic Typing: Type checks happen during program execution (at runtime). Languages like Python, JavaScript, and Ruby are dynamically typed. This is like discovering a structural problem only after the building is constructed and under load. It offers more flexibility and faster prototyping but can lead to surprising runtime errors.

Let's see this in code. The trade-offs become much clearer with a concrete example.

Static vs. Dynamic Typing: A Guide for App Leaders

Now, let's look at the code examples from the same article to solidify your understanding.

Read the section Seeing the Difference in Real Code. Pay close attention to the JavaScript vs. TypeScript example, as it directly relates to your current expertise. Notice how the same logical error is caught by one but not the other. The article uses a Python vs. Java example for the backend. In this context, the behavior shown for Java is conceptually identical to how C# would behave, since both are statically-typed languages from the same family.

The calculateTotal("$100", 5) example is perfect. In JavaScript (dynamic), this runs without error but produces the nonsensical result "$1005". In TypeScript (static), this code wouldn't even compile; it's an error caught before runtime, saving you from a potentially subtle and costly bug in production.


Strong vs. Weak Typing: The "How" of Type Rules

The static/dynamic distinction is about when checks happen. Our second axis, strong vs. weak typing, is about how strict the language is with its type rules, specifically regarding automatic type conversions. This is also known as type coercion.

  • Strong Typing: In a strongly-typed language, operations between incompatible types are generally forbidden. If you try to add a number to a string, the language will raise an error rather than trying to guess what you meant. Python is a great example of this.

    
    
    
    # In Python (Strongly typed)
    result = "5" + 5
    
    
    
    # Raises a TypeError: can only concatenate str (not "int") to str
    
  • Weak Typing: In a weakly-typed language, the interpreter will try its best to make incompatible types work together by implicitly coercing (converting) one of them. JavaScript is the classic example.

    // In JavaScript (Weakly typed)
    let result = "5" + 5;
    // No error. JS coerces the number 5 to the string "5"
    // result is "55"
    

It's crucial to understand that these two axes are independent. You can have languages that fit into any of the four resulting quadrants. Let's revisit our guide, which makes this exact point.

Static vs. Dynamic Typing: A Guide for App Leaders

This final section of the article clearly separates the two concepts we've been discussing.

Read the short but vital section Strong and weak typing. This explicitly states the difference between the two axes we've discussed.


The Comparative Map

Now we can put everything together and build the mental map that was our goal. We can classify languages on a 2x2 grid.

A 2x2 matrix categorizing programming languages by their type systems. The vertical axis represents static vs. dynamic typing, and the horizontal axis represents strong vs. weak typing.

Let's place our languages of interest onto this map and justify their positions:

  • TypeScript & C# (Static / Strong):

    • Static: Both languages check types at compile time. You declare types for variables and function signatures, and the compiler enforces them.
    • Strong: Both languages have strict rules about type compatibility. You cannot, for example, implicitly assign a string to a variable that expects a number without an explicit cast. They prevent unpredictable coercion. They sit together in the top-right quadrant.
  • Python (Dynamic / Strong):

    • Dynamic: You don't declare variable types in Python. An object has a type, but a variable is just a name. Type checks happen when you try to do something with the object at runtime.
    • Strong: As we saw in the example "5" + 5, Python refuses to guess. It throws a TypeError because the operation is not defined for a string and an integer. This makes its runtime behavior more predictable than a weakly-typed language. It belongs in the bottom-right quadrant.
  • JavaScript (Dynamic / Weak):

    • Dynamic: Like Python, types are checked at runtime. This is the behavior you're familiar with from plain JavaScript.
    • Weak: As we also saw, JavaScript is famous for its aggressive type coercion. "5" + 5 becomes "55", and "5" - 3 becomes 2. This flexibility can be powerful, but it's also a common source of bugs. JavaScript sits in the bottom-left quadrant.

Your primary language, TypeScript, is an interesting case. It's a statically typed layer built on top of a dynamically and weakly typed language (JavaScript). Its main purpose is to bring the safety of the Static/Strong quadrant to the JavaScript ecosystem.


Conclusion

In this lesson, we've dissected the crucial concept of type systems along two independent axes.

  • Key Takeaway 1: Static vs. Dynamic is about when types are checked—before runtime (static) or during runtime (dynamic). Static typing catches errors early, while dynamic typing offers more flexibility.
  • Key Takeaway 2: Strong vs. Weak is about how strict the type rules are. Strong typing prevents operations on incompatible types, while weak typing tries to make them work through implicit conversion (coercion).
  • Key Takeaway 3: The Map: TypeScript and C# are statically and strongly typed. Python is dynamically and strongly typed. This means transitioning from TypeScript to Python will involve giving up compile-time checks but retaining a strict, predictable runtime.

This framework is a massive step towards your goal of becoming language-agnostic. When you encounter a new language, asking "Is it static or dynamic? Strong or weak?" will tell you a great deal about how to write code in it, what kind of errors to expect, and what its philosophical trade-offs are.

In our next lesson, we will go one level deeper. Now that we understand the language's rules (paradigms and types), we will ask how the computer actually executes our code. We'll compare how TypeScript (via Node.js), Python, and C# run code and manage memory, connecting these type system decisions to their real-world performance and behavior.