Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

What is Assignability in TypeScript?

When you start learning programming, you might come across the term "assignability" in TypeScript. Assignability is a concept in TypeScript that deals with how values of different types can be assigned to variables, function parameters, or returned from functions. In this blog post, we will discuss assignability in depth, with actual code examples and analogies to help you understand the concept better.

Understanding Variables and Types

In programming, we use variables to store and manipulate data. Variables are like containers that can hold different kinds of data. For example, you can have a variable that holds a number, another variable that holds a string (text), and so on. In TypeScript, the type of data a variable can hold is called its "type."

To create a variable in TypeScript, we use the let keyword, followed by the name of the variable, and then an optional type annotation, which is a colon followed by the type. Here's an example:

let age: number;
let name: string;

In this example, we have created two variables: age and name. The age variable has a type of number, meaning it can hold numeric values. The name variable has a type of string, meaning it can hold text.

What is Assignability?

Assignability is the ability to assign a value of one type to a variable of another type. In other words, it's the set of rules that TypeScript follows to determine whether a value can be assigned to a variable or not.

Assignability is important because it helps maintain the integrity of our code. By ensuring that only values of the correct type can be assigned to variables, TypeScript helps us avoid many common errors that can occur when working with data.

To illustrate the concept of assignability, let's use an analogy. Imagine you have a set of containers, each designed to hold a specific type of liquid. Some containers are designed for water, others for oil, and so on. Assignability is like the rule that says you can only pour water into the water container, oil into the oil container, and so on. If you try to pour water into the oil container, you'll get an error because the types are not compatible.

In TypeScript, assignability rules help us ensure that we only assign values of the correct type to our variables. This helps prevent unexpected errors and makes our code more robust.

Assignability Rules in TypeScript

Now that we understand what assignability is, let's look at the rules TypeScript follows to determine whether a value can be assigned to a variable or not.

Rule 1: Same Type

If the source type and the target type are the same, they are assignable.

For example, if you have a variable of type number and you want to assign a numeric value to it, TypeScript will allow the assignment because the types are the same.

let age: number = 30; // This is allowed because age is of type number and 30 is also a number.

Similarly, if you have a variable of type string and you want to assign a string value to it, TypeScript will allow the assignment.

let name: string = "Alice"; // This is allowed because name is of type string and "Alice" is also a string.

Rule 2: Subtypes

A value of a subtype can be assigned to a variable of a supertype.

In TypeScript, some types are considered subtypes of other types. For example, null and undefined are subtypes of all other types. This means that you can assign a value of null or undefined to a variable of any type.

let age: number = null;      // This is allowed because null is a subtype of number.
let name: string = undefined; // This is allowed because undefined is a subtype of string.

Note that this rule applies to other subtypes as well, not just null and undefined. For example, in TypeScript, all literal types (like 42, "hello", true) are subtypes of their corresponding primitive types (number, string, boolean).

Rule 3: Any Type

The any type is a special type in TypeScript that is assignable to and from all other types.

This means that you can assign a value of any type to a variable of type any, and you can also assign a value of type any to a variable of any other type.

let anything: any;

anything = 42;          // This is allowed because 42 is a number and any can accept any type.
anything = "Hello";     // This is allowed because "Hello" is a string and any can accept any type.

let age: number = anything; // This is allowed because anything is of type any, which is assignable to any other type.

It's important to note that using the any type can be dangerous because it essentially disables TypeScript's type checking. It's better to use more specific types whenever possible to maintain the safety and predictability of your code.

Rule 4: Structural Typing

TypeScript uses structural typing to determine assignability for complex types like objects and functions. This means that two types are considered compatible if they have the same structure, even if they have different names.

For example, consider the following two interfaces:

interface Person {
  name: string;
  age: number;
}

interface Employee {
  name: string;
  age: number;
}

Even though Person and Employee are different types, they have the same structure (both have a name property of type string and an age property of type number). Therefore, in TypeScript, a value of type Person can be assigned to a variable of type Employee, and vice versa.

let person: Person = { name: "Alice", age: 30 };
let employee: Employee = person; // This is allowed because Person and Employee have the same structure.

person = employee; // This is also allowed for the same reason.

This rule also applies to functions. Two functions are considered compatible if they have the same parameter types and return type. For example:

type GreetingFunction = (name: string) => string;

let greet1: GreetingFunction = (name: string) => `Hello, ${name}!`;
let greet2: GreetingFunction = (name: string) => `Hi, ${name}!`;

// The following assignment is allowed because greet1 and greet2 have the same parameter types and return type.
greet1 = greet2;

Conclusion

Assignability is an important concept in TypeScript that helps maintain the integrity of your code by ensuring that only values of the correct type can be assigned to variables, function parameters, or returned from functions. By understanding assignability and its rules, you can write more robust and error-free code in TypeScript.

In this blog post, we discussed the main rules for assignability in TypeScript:

  1. Same type: Values of the same type can be assigned to each other.
  2. Subtypes: Values of a subtype can be assigned to a variable of a supertype.
  3. Any type: The any type can be assigned to and from all other types.
  4. Structural typing: Complex types like objects and functions are considered compatible if they have the same structure.

Remember to always use appropriate types for your variables and avoid using the any type whenever possible. By doing so, you can leverage TypeScript's powerful type system to write safer and more predictable code.