Skip to content

Type System

Type Systems#

A type system is a fundamental feature of a programming language that serves to classify and manage all data and operations within a program. By assigning a "type"—such as integer, string, boolean, or user-defined types—to every value, variable, and function, the type system helps both humans and computers understand what kinds of data can be stored and how they can be manipulated. This categorization is critical for catching bugs early (such as trying to add a number to a string), enforcing correct program behavior, and improving performance through optimizations. In essence, the type system acts as a set of rules that govern how data can be used, helping to prevent errors and create more robust, reliable code.

Type inference is a feature in many modern programming languages that lets the compiler or interpreter figure out the type of a variable based solely on the value you assign to it. For example, writing var name = "Alice" tells the compiler that name should be treated as a String, even though you didn’t explicitly state its type. This makes code shorter and easier to read, while still maintaining type safety.

The diagram below explains how type inference works and when you might need to declare a type explicitly:

graph TD
    A[Variable Declaration] --> B{Type Inference}
    B --> C["Compiler/Interpreter Analyzes Value"]
    C --> D[Determines Appropriate Type]
    D --> E[Assigns Type Automatically]

    F[Ambiguous Cases] --> G[Explicit Type Declaration Required]
    G --> H[Developer Provides Clarity]

    style B fill:#e3f2fd
    style E fill:#c8e6c9
    style G fill:#fff3e0

When you declare a variable, the type system determines how (or if) it can deduce that variable’s type.

Type Inference (Automatic):

  • You start by declaring a variable—let’s say, var age = 30;.
  • If you do not state the type explicitly (using syntax like var or let without a type), the compiler or interpreter looks at the value you assigned.
  • By analyzing this value (for example, the number 30), the system figures out the most appropriate type (like int for whole numbers or String for text).
  • This type is then assigned to the variable behind the scenes, so your code remains concise, and you don’t have to repeat information the compiler can already see.

Explicit Declaration (When Required):

  • Sometimes, however, the value you assign doesn’t provide enough information for the system to be certain about the type. For example, if you write var z = null; or use a complex expression, it can’t safely guess.
  • In these ambiguous cases, the type system requires you to specify the type explicitly—such as String? z = null; to avoid confusion or subtle bugs.
  • Declaring the type explicitly is also helpful for code readability: it tells other programmers (and your future self) exactly what you intend that variable to be.

In summary:

Type inference saves you from writing repetitive type annotations when the type is obvious, making code shorter and cleaner. But, whenever the computer can't be sure about the type, you must explicitly specify it. This balance combines the benefits of convenience and safety, leading to both concise and reliable code.

Primitive Data Types#

A primitive data type is a basic type built into a programming language. These types represent the simplest forms of data and act as the building blocks for handling and manipulating information in a program. Common primitive types let you store things like text, numbers, and logic values.

Here are the most common primitive data types, with a simple explanation and code examples in several popular languages:

  • String: Used for text, like words or sentences.
final var phrase = "I'm a phrase";
val phrase = "I'm a phrase"
const phrase = "I'm a phrase";
const phrase = "I'm a phrase";
let phrase = "I'm a phrase"
phrase = "I'm a phrase"
  • Float: A decimal number with limited precision (32 bits). Useful for storing numbers with a fractional part (e.g., 3.14).
final var fl = 3.14F;
val fl = 3.14F

There's no separate float type in TypeScript. All decimals use the general number type.

There's no float type in Dart. Use double for decimal numbers.

let fl: Float = 3.14
fl = 3.14
  • Double: A decimal number with more precision (64 bits). Used when you need to store larger decimal numbers accurately.
final var double = 1.79769313486231570e+308;
val double = 1.79769313486231570e+308
// Underscores may be used for readability.
// val myReadableDouble = 1.797_693_134_862_315_70e+308

There's no separate double type in TypeScript. The general number type is used.

const double = 1.79769313486231570e+308;
let double = 1.79769313486231570e+308

Python doesn't have a double type; use float for decimal numbers of any size.

  • Short: A small, whole number without decimals (16 bits). Not available in every language.
// Using Short to store a small integer.
final Short ten = 10;
val ten: Short = 10

There's no short type in TypeScript (number covers all cases).

No short type in Dart; use int for integer numbers.

let ten: CShort = 10

Python does not have a special short type; use int.

  • Integer: A regular whole number without decimal points (32 bits).
final var myInt = 64000;
val myInt = 64000

There's no specific integer type in TypeScript; use number.

const myInt = 64000;
let myInt = 64000
myInt = 64000
  • Long: A whole number that can store much larger values (64 bits).
final var aLargeNumber = 9223372036854775807L;
val aLargeNumber = 9223372036854775807L

There's no long type in TypeScript; number is used for all numbers.

No long type in Dart; use int for large integers.

let aLargeNumber: UInt64 = 9223372036854775807

Python's int type supports large numbers by default.

  • Boolean: A value that can only be true or false. Useful for logic and conditions.
final var isDarkMode = true;
final var isLightMode = false;
val isDarkMode = true
val isLightMode = false
const isDarkMode = true;
const isLightMode = false;
const isDarkMode = true;
const isLightMode = false;
let isDarkMode = true
let isLightMode = false
isDarkMode = True
isLightMode = False

Uninitialized Variables#

An uninitialized variable is a variable that has been declared but has not yet been given a value. In most typed languages, you must specify the data type when you declare a variable without assigning a value; this tells the compiler what kind of data the variable will hold in the future.

Here’s how to declare an uninitialized variable:

String helloWorld;
val helloWorld: String
let helloWorld: String;
String helloWorld;
// For typed variables, you can use final to make it immutable.
var helloWorld: String

Python does not support uninitialized variables; you must always assign a value at declaration.