The Complete Guide to TypeScript Types
Tags: webdev, programming, frontend, typescript
Published: 2024-04-19 20:10:31

---
title: The Complete Guide to TypeScript Types
published: true
date: 2024-04-19 11:02:10 UTC
tags: webdevelopment,programming,frontenddevelopment,typescript
canonical_url: https://antondevtips.com/blog/the-complete-guide-to-typescript-types
---

This blog post makes a deep dive into TypeScript’s type system, exploring basic types, advanced types, and some special cases, with various examples to help you master TypeScript’s type system.

### Primitive types

TypeScript has 3 **primitive types** : number, boolean and string, same as in JavaScript. According to official TypeScript docs: we should always use lowercase names for primitive types, as Number, Boolean and String are special built-in types.

- number - represents integer and float numbers under a single type, like: 5 or 5.2
- boolean - represents a true of false value
- string - represents text values, like "Some text here"

Here is how to define variables of **primitive types** :

```ts
const total: number = 100;
const isActive: boolean = true;
const userName: string = "Anton";
```

Alternatively we can define variables like this, where types will be inferred automatically:

```ts
const total = 100;
const isActive = true;
const userName = "Anton";
```

### Enums

**Enums** in TypeScript provide a way to group a set of named constants together under a single type. **Enums** make the code easier to read and maintain for variables that have a defined set of values, instead of using magic numbers or strings. TypeScript supports both **numeric** and **string**  enums.

By default, enums in TypeScript are numeric. **Numeric enums** map names to numbers, starting from zero and incrementing by one for each member. Although you can manually set the value of its members if needed.

```ts
enum Status {
    New, // 0
    InProgress, // 1
    Completed // 2
}

const taskStatus: Status = Status.InProgress;
console.log(taskStatus); // Outputs: 1
```

**String enums** , on the other hand, map names to strings. Unlike numeric enums, string enums must be manually initialized with a string value.

```ts
enum Status {
    New = "NEW",
    InProgress = "IN_PROGRESS",
    Completed = "COMPLETED"
}

const taskStatus: Status = Status.InProgress;
console.log(taskStatus); // Outputs: IN_PROGRESS
```

### Object Types

**Object types** in TypeScript groups a set of properties under a single type.

Object types can be defined either using type alias:

```ts
type User = {
    id: number;
    name: string;
};

const user: User = { id: 1, name: "Anton" };
```

Or interface keyword:

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

const person: Person = { name: "Anton", age: 30 };
```

**Interfaces** are extendable and can inherit from other interfaces. You can extend them by declaring the same interface multiple times, or by extending them using the extends keyword. **Classes** can implement interfaces.

The **type** alias in TypeScript can be used to define a type for a variety of structures, not just objects. This includes primitives, unions, intersections, tuples, and more. While **type** provides more flexibility in defining complex types, you cannot reopen a **type** to extend or add new properties.

Whether to use type or interface - it all depends on a specific needs of a project or a personal or team preference.

### Functions

TypeScript enhances **functions** by allowing developers to specify types for parameters and return values. This ensures that functions are called with the correct types of arguments and that their return types are consistent with expectations.

```ts
function sayHello(name: string): string {
    return `Hello, ${name}!`;
}

const message: string = sayHello("Anton");
```

Functions can accept arguments and return a value using any types.

### Arrays

**Arrays** in TypeScript allow to store multiple values of the same type in a list.

TypeScript allows **array** creation for primitive and object types:

```ts
const numbers: number[] = [1, 2, 3, 4, 5];
const names: string[] = ["Anton", "Jack", "Nick"];

type User = {
    id: number;
    name: string;
};

const users: User[] = [
    { id: 1, name: "Anton" },
    { id: 2, name: "Jack" },
];
```

Also you can use a generic array type Array<elementType> for creating arrays:

```ts
const scores: Array<number> = [1, 2, 3, 4, 5];
const cities: Array<string> = ["London", "New York", "Kyiv"];
```

### Type Assertions

**Type assertions** in TypeScript allow you to tell the compiler that you know better the type of an object or variable than TypeScript can infer. Essentially, a type assertion is like a type cast in other languages, but it performs no special checking or restructuring of data. It has no runtime impact and is used purely by the TypeScript compiler for type checking.

You can use as keyword to perform type assertion:

```ts
const value: any = "some text here";
const length: number = (value as string).length;
```

Alternatively you can use <type> syntax:

```ts
const value: any = "some text here";
const length: number = (<string>value).length;
```

> _Important tip: you can’t use_ _<type> syntax in \*.tsx files in React._

> _Because type assertions have no impact and type checking during runtime: there won’t be an exception or null if the type assertion is wrong._

### Union Types

**Union type** in TypeScript is a type that is formed from two or more other types. A variable of **union type** can have one of the types from the union.

Here’s a simple example where a variable can hold either a number or a string:

```ts
let id: number | string;
id = 100; // This code is correct
id = "200"; // This code is correct

// TypeScript Error: Type 'boolean' is not assignable to type 'string | number'.
id = false;
```

**Unions** are particularly useful in function parameters, allowing functions to accept arguments of different types:

```ts
function printNumber(value: number | string) {
    console.log(`Number: ${value}`);
}

printNumber(100); // Works with a number
printNumber("200"); // Also works with a string
```

When using **unions** , TypeScript will only allow to access properties or methods that are common to all types in the union. To use type-specific properties or methods, you need to use type guards:

```ts
function getLength(obj: string | string[]) {
    if (typeof obj === "string") {
        return obj.length; // Return length of a string
    }

    return obj.length; // Return legnth of string array
}
```

**Unions** are also useful when combining string literals. A literal in TypeScript is a special type for constant string, for example:

```ts
let text: "TypeScript" = "TypeScript";
text = "TypeScript"; // This code compiles

// TypeScript Error: Type '"JavaScript"' is not assignable to type '"TypeScript"'.
text = "JavaScript";
```

By combining literals into unions you can express that a variable can only accept a certain set of values:

```ts
function print(value: string, align: "left" | "right" | "center") {
    // ...
}

print("TypeScript types", "left");

// TypeScript Error: "align" parameter should be one of: "left" | "right" | "center"
print("TypeScript types", "midde");
```

### Intersection Types

**Intersection types** in TypeScript allow you to combine multiple types into one. An **intersection type** can be created by combining multiple interface types using & operator:

```ts
interface Person {
    name: string;
}

interface ContactDetails {
    email: string;
    phone: string;
}

type Customer = Person & ContactDetails;

const customer: Customer = {
    name: "Anton",
    email: "anton@devtips.com",
    phone: "1234567890"
};
```

In this example a Customer type is an **intersection type** that combines all properties from Person and ContactDetails interfaces.

Intersections are not limited just to interfaces, they can be used with other types as well, including primitives, unions, and other intersections.

### Tuple Types

**Tuple types** in TypeScript is an array with a fixed number of elements and types at specific positions. **Tuples** are particularly useful when you need to return multiple values from a function or when you want to represent a data structure with a fixed number of elements of specific types.

```ts
const person: [string, number] = ["Anton", 30];
```

This **tuple** represents a person’s information: name and age. The first element must be a string, and the second must be a number.

Tuples are particularly useful when you need to return multiple values from a function:

```ts
function getPersonDetails(personId: number): [number, string, string] {
    // Simulate returning a value from an API:
    return [personId, "Jack Sparrow", "Captain"];
}

const [name, id, position] = getPersonDetails(1);
console.log(name); // Jack Sparrow
console.log(id); // 123
console.log(position); // Captain
```

### Special Types: any, unknown

The **any** keyword in TypeScript tells the compiler to trust you about the type of a variable, and it won’t try to check its type during compilation. A variable of type any is like a JavaScript variable, freely mutable and usable in any context.

Here is an example of using a variable of type  **any** :

```ts
let data: any = "Hello, world!";
data = 42; // This code compiles without errors.

// Runtime error! Numbers don't have a toLowerCase method.
console.log(data.toLowerCase());
```

While there are certain scenarios, you should avoid any at all costs, use it only as the last available option.

A slightly better option is to use **unknown** type, which is a bit more type-safer. While it represents any value (just like any), TypeScript will ensure that you check the type of the variable before using it:

```ts
let data: unknown = "Hello, world!";
data = 42; // This code compiles without errors.

// This won't compile:
// console.log(data.toLowerCase());

if (typeof data === "string") {
    console.log(data.toLowerCase()); // Now it compiles!
}
```

If you want to learn more about **any** and **unknown** I have a dedicates blog posts about them:

- [TypeScript: The Danger of Using the Any Keyword](https://antondevtips.com/blog/typescript-the-danger-of-using-the-any-keyword)
- [TypeScript: Any vs Unknown — Understanding the Difference](https://antondevtips.com/blog/typescript-any-vs-unknown-understanding-the-difference)

### Special Types: never, null, undefined

The **never** type represents values that never occur. It’s a type that is used for functions that never ends or always throw an exception.

```ts
function print(value: string): never {
    console.log(value);
    while (true) {}
}

function throwError(message: string): never {
    throw new Error(message);
}
```

In TypeScript null and undefined are types that represent absence of a value. null and undefined can be used for all types, including primitive and object types.

```ts
// Using union type to allow null
let age: number | null = null;
age = 25; // OK
age = null; // OK

let address: string | undefined;
address = "123 Main St"; // OK
address = undefined; // OK
```

The behavior of these types depends on using strictNullChecks setting. It is recommended to turn strictNullChecks **on** for making code safer: when value can be null or undefined - you need to test for this value before accessing a variable or property.

```ts
interface User {
    id: number;
    name: string;
}

// A function that may return a User, null, or undefined
function getUser(id: number): User | null | undefined {
    // ... Skip code for breviaty
}

const userID = 1;
const user = getUser(userID);

if (user === undefined) {
    console.log("Error fetching user data.");
} else if (user === null) {
    console.log("User not found.");
} else {
    console.log("User found: ${user.name}");
}
```

### Summary

TypeScript has a rich type system that includes the following types:

- Primitives: number, boolean, string
- Enums
- Objects
- Functions
- Arrays
- Union Types, Intersection Types, Tuple Types
- Special types: any, unknown, never, null, undefined

Hope you find this blog post useful. Happy coding!

_Originally published at_ [_https://antondevtips.com_](https://antondevtips.com/blog/the-complete-guide-to-typescript-types)_._

### After reading the post consider the following:

- [Subscribe](https://antondevtips.com/blog/the-complete-guide-to-typescript-types#subscribe) **to receive newsletters with the latest blog posts**
- [Download](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/frontend/typescript/types-guide) **the source code for this post from my** [github](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/frontend/typescript/types-guide) (available for my sponsors on BuyMeACoffee and Patreon)

If you like my content —  **consider supporting me**

Unlock exclusive access to the source code from the blog posts by joining my **Patreon** and **Buy Me A Coffee** communities!

[![](https://cdn-images-1.medium.com/max/233/1*GSZFx05RDUWr5pn_E9bK8w.png)](https://www.buymeacoffee.com/antonmartyniuk)

[![](https://cdn-images-1.medium.com/max/229/1*8tJk9eYCJrkzoAJw2cILSA.png)](https://www.patreon.com/bePatron?u=73769486)