Posted in

Built-in types in TypeScript

Built-in types in TypeScript
Built-in types in TypeScript

Data types are fundamental in programming, helping us in categorizing the type of data a variable can store. Consider it similar to labeling your storage boxes: some for books, some for gadgets, others for tools, etc. In TypeScript, just like in many other languages declaring data types is absolutely essential for writing clear, deterministic, predictable, and error-free code.

TypeScript has two primary categories of data types:

Built-in Types: These are the pre-defined types in TypeScript that cover everyday data categories such as numbers, strings, and true/false.

User-Defined Types: These are custom types (your own types) you define yourself to fit the your specific needs of your application or suit your application’s specific requirements

In this article, we will concentrate on learning and understanding the built-in types of TypeScript in depth.

Getting Started with Data Types in TypeScript

You have probably written a simple program to add two numbers. When you declared those numbers, you were using a data type. It’s how we tell the computer what kind of information we are dealing with. Languages such as C, C++, and Java are also based almost entirely on this concept.

TypeScript does the same, enabling you to define data types for variables and functions explicitly. When you declare a variable, TypeScript determines its type in two ways:

  • Explicitly: You manually write out the data type. This is like telling TypeScript directly, “Hey, this variable will hold a number!”
  • Implicitly: TypeScript “infers” the data type based on the value you initially assign to the variable. If you write let age = 30;, TypeScript automatically knows age is a number without you having to type : number. While convenient, explicit typing often makes your code more readable and helps prevent subtle bugs.

Let’s dive into the built-in TypeScript data types:

Number

The number type in TypeScript covers all kinds of numbers, whether they are whole numbers (integers) or numbers with decimal points (floating-point numbers). It’s represented by the keyword number.

Example:

let score: number = 100; // A whole number
let price: number = 29.99; // A number with a decimal

console.log(score);
console.log(price);

Output:

100
29.99

In this example, we declared `score` and `price` as `number` types since they are supposed to contain number values. If you try to assign something that isn’t a number to them, TypeScript will flag it as an error.

String

The string type is used for text handling. You can enclose string values in either single quotes (') or double quotes ("). The keyword for this type is, you guessed it, string.

Example:

let firstName: string = 'Alice'; // Using single quotes
let lastName: string = "Smith"; // Using double quotes
let greeting: string = `Hello, ${firstName} ${lastName}!`; // Template literals for easy combining

console.log(firstName);
console.log(lastName);
console.log(greeting);

Output:

Alice
Smith
Hello, Alice Smith!

Here, firstName, lastName, and greeting are all string variables, designed or meant to store textual data. See how template literals (using backticks `) make it really easy to embed variables directly into your strings!

Boolean

The boolean type is simple: it represents values that can only be true or false. It’s incredibly useful for logic and decision-making in your code. The keyword is boolean.

Example:

let isActive: boolean = true;
let hasPermission: boolean = false;

console.log(`Is active: ${isActive}`);
console.log(`Has permission: ${hasPermission}`);

Output:

Is active: true
Has permission: false

In this case, isActive and hasPermission are boolean variables, ideal for storing true/false conditions.

Void

The void type is a bit special. It’s used when a function doesn’t return any value or anything. Consider it like a function that performs an action but doesn’t return anything back. The keyword is void.

You might also see void used with variables, but it’s much less common and typically not recommended because you can only assign undefined (or null if strictNullChecks is off) to a void variable.

Example of void in a function:

function showMessage(message: string): void {
    console.log(message);
}

showMessage("This function just displays a message.");

// What happens if we try to capture its return value?
let result: void = showMessage("Another message.");
console.log(result); // Output: undefined

Output:

This function just displays a message.
Another message.
undefined

The showMessage function above prints a message to the console, but it doesn’t return any data or anything. That’s why its return type is void. When you try to assign its “return value” to result, result will just be undefined because there’s nothing to return.

Why assigning to a void variable is tricky:

let myVoidVariable: void = undefined;
// myVoidVariable = 5; // Error: Type '5' is not assignable to type 'void'.

This error shows that a void variable can’t hold a number (or most other types). This is why void is mostly used for function return types.

Null

The null type represents the intentional absence of any object value. It literally means “nothing” or “no value.” It’s different from undefined, which often means a variable hasn’t been assigned any value yet. The keyword is null.

Example:

let userAddress: string | null = null; // Can be a string or null

function getUserAddress(userId: number): string | null {
    // In a real application, you'd fetch the address here.
    // For this example, let's say user 123 has no address.
    if (userId === 123) {
        return null;
    } else {
        return "123 Main St.";
    }
}

userAddress = getUserAddress(123);
console.log(`User address for 123: ${userAddress}`); // Output: User address for 123: null

userAddress = getUserAddress(456);
console.log(`User address for 456: ${userAddress}`); // Output: User address for 456: 123 Main St.

In this case, userAddress can either hold a string (an actual address) or null (if no address is found). This is a common pattern in TypeScript when a variable might not have a value sometimes.

Important Note: By default, in TypeScript, null and undefined are sub-types of all other types. This means you could assign null to a number variable, for example. However, it’s highly recommended to enable strictNullChecks in your tsconfig.json. This makes your code safer by forcing you to explicitly handle null and undefined values, preventing unexpected errors. With strictNullChecks enabled, you’d have to use a union type (like string | null) as shown in the example above.

Undefined

The undefined type indicates that a variable has been declared but not assigned a value yet. It’s the default value for uninitialized variables.

Example:

let favoriteColor: string; // Declared but not assigned

console.log(favoriteColor); // Output: undefined

favoriteColor = "blue";
console.log(favoriteColor); // Output: blue

In this example, favoriteColor is undefined until we assign a value to it.

Similar to null, enabling strictNullChecks is crucial for safely working with undefined. Without it, you could assign undefined to a number variable, which might lead to runtime issues.

Any

The any type is TypeScript’s “escape hatch.” It allows you to opt out of type checking for a given variable. When you use any, TypeScript essentially says, “I’m not going to check the type of this variable, you’re on your own!” This can be helpful in certain situations, like when dealing with data from external sources where you don’t know the exact structure, or when converting a JavaScript project to TypeScript.

However, using any too much defeats the purpose of TypeScript’s type safety. It’s generally best to use any sparingly and only when absolutely needed.

Example:

let mixedValue: any;

mixedValue = 10;        // No error, can be a number
console.log(mixedValue);

mixedValue = "hello";   // No error, can be a string
console.log(mixedValue);

mixedValue = true;      // No error, can be a boolean
console.log(mixedValue);

// You can even call it like a function or access properties that might not exist
// This is where 'any' can lead to runtime errors if you're not careful!
mixedValue.someMethod(); // This would cause a runtime error if 'mixedValue' is not an object with 'someMethod'

Output:

10
hello
true
// (Potentially a runtime error here depending on the value of mixedValue)

As you can see, mixedValue can store any type of data without TypeScript complaining. Although this flexibility seems nice, it means you lose all the benefits of type checking. Use any with caution!

Conclusion

Understanding these built-in TypeScript data types is an important step towards becoming a master with TypeScript. Explicitly declaring data types makes your code more readable, understandable, and less prone to errors. While TypeScript’s inference can be helpful, knowing when and how to use explicit types will greatly improve the quality and maintainability of your code.

Do you feel more confident about TypeScript’s built-in types now? What is one type you think you with use most frequently in your projects?

You can also follow: Basic Types

Leave a Reply

Your email address will not be published. Required fields are marked *