# Functions in TypeScript

![ddb2af52.webp](https://cdn.hashnode.com/res/hashnode/image/upload/v1643662982228/65gUzA2VT.webp align="left")

## WHAT ARE FUNCTIONS?

> **Functions are the fundamental building blocks of any application in JavaScript. They’re how you build up layers of abstraction, mimicking classes, information hiding, and modules.**

> **In TypeScript, while there are classes, namespaces, and modules, functions still play a key role in describing how to do things.**

## WHAT TYPESCRIPT ADDS?

> **Functions are the primary means of passing data around in JavaScript. TypeScript allows you to specify the types of both the input and output values of functions.**

> **TypeScript also adds some new capabilities to the standard JavaScript functions to make them easier to work with.**

## SYNTAX AND STRUCTURE:

In TypeScript, function definition consists of a function name, its parameters with types, and its return type (which can be inferred by TypeScript).

### DECLARE AN ARROW FUNCTION:

Following is the syntax to declare a function in TypeScript:

```typescript
const functionName = (param1: string): string => {
  // ...
  return param1;
};

// functionName = Name of the function
// param1 = Name of the parameter (optional)
// (...): string = Return type of the function
```

In the above code, the syntax `(param1: string): string =>` means a function with one parameter, named `param1`, of type `string`, that has a return value of type `string`.

If you don't specify the return type, TypeScript automatically infers the return type for you as shown below:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643737505137/VsiPbTT-9.png align="left")

Here, `const functionName: (param1: string) => string` means, a function with a name `functionName` with one parameter named `param1` of type `string` that has a return value of type `string`.

### DECLARE A FUNCTION WITH `function` KEYWORD:

Declaring a function with the `function` keyword is almost similar to an arrow function.

Take a look at the following code:

```typescript
function functionName(param1: string): string {
  // ...
  return param1;
}
// functionName = Name of the function
// param1 = Name of the parameter (optional)
// (...): string = Return type of the function
```

## TYPE ANNOTATIONS:

> When you declare a function, you can add type annotations after each parameter to declare what type of parameters the function accepts. You can add return type annotations to the function as well.

> **Parameter type annotations go after the parameter name. Return type annotations appear after the parameter list.**

### PARAMETER TYPE ANNOTATIONS:

Take a look at the following code:

```typescript

const add = (a: number, b: number) => {
  return a + b;
};

console.log(add(1, 2));
```

In the above code, we declare an `add` function that accepts parameters `a` and `b` that is of type `number`.

So, if you try to break the rule and pass `string` instead of the `number`, you will get a compilation error as follows:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643738509836/S_wMSUCm_.png align="left")

Also, if you try to add parameters more than what a function is accepting, you will get a compilation error, unlike JavaScript.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643738670780/KewHF5Mxo.png align="left")

### RETURN TYPE ANNOTATIONS:

Although we usually don’t need a return type annotation because TypeScript will infer the function’s return type based on its return statement. In some cases, you have to explicitly specify a return type for documentation purposes to prevent accidental changes or just for personal preference.

```typescript
const returnANumber = (): number => {
  return 1;
};
```

Here, we are specifying that the `returnANumber` will return a value with a `type` `number`.

Now, if you specify the return type but don't return a value with valid `type`, TypeScript will throw a compilation error as follows:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643740462239/B0VJ99DJg.png align="left")

#### IDE SUPPORT FOR RETURN TYPE:

The advantage of knowing the return type of a function is you get great IDE support if you want to do more operations on the value that is being returned.

For example,

```typescript
let parseRange = (
  range: string
): {
  start: number;
  end: number;
} => {
  let [start, end] = range.split("-");
  return {
    start: parseInt(start),
    end: parseInt(end),
  };
};

let parsedData = parseRange("1-5");
```

In the above example, we have explicitly mentioned the return type of the `parseRange` function. However, even if we don't specify the return type, TypeScript will infer the return type for us.

If we try to access the start or end keys on the `parsedDate` variable, we will get autosuggestion from an IDE because TypeScript knows the return type of the `parseRange` function.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643741675666/eDJmAu1wP.png align="left")

#### `void` RETURN TYPE:

Similar to languages like Java, `void` is used when there is no data. For example, if a function does not return any value then you can specify `void` as a return type or let TypeScript infer the return type as `void`.

```typescript
const helloWorld = () => {
  console.log("Hello World");
};

let sayHello = helloWorld();

console.log(sayHello); // this will print undefined
```

You will get a compilation error if you attempt to return any value other than `void` after specifying `void` as a return type for that function:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643783585562/HOhDbg4Cj.png align="left")

You can only return `undefined` if you specify `void` as the return type. The following image shows valid and invalid return statements for a function with the return type of `void`.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643783781425/wtEnghxj7.png align="left")

> **Remember the Rule: "**`void` is the return type of a function/method that doesn’t explicitly return anything".

> **When no return statement is provided and no explicit return type is specified in the function or method, it infers a** `void` return type automatically.

## FUNCTION AS A TYPE:

It is possible to assign a type to a variable that we want to use as a function with a specific parameter and return type. Here's how to declare one:

```typescript

let add: (a: number, b: number) => number;

add = (a: number, b: number) => {
  return a + b;
};
```

In the above code, we are declaring a variable `add` and have assigned a type `(a: number, b: number) => number` ***(This is not an arrow function or a function declaration. Here, the left side of the*** `=>` are the parameters that the function expects and the right side of the `=>` is the return type of that function)

Using the `add` the variable we declared earlier, we can assign a function to it as a `value`.

TypeScript will throw an error stating that this variable only allows two parameters if we try to add another.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643802633672/xNQ48EMPE2.png align="left")

### PASS `Function` AS A PARAMETER:

Take a look at the following code:

```typescript
const sendMessage = (cb: (a: string) => void) => {
  cb("Hello, World");
};

sendMessage((str)=>{
  console.log(str);
});
```

Here, the `sendMessage` function has a parameter named `cb` (callback function) with one parameter named `a`, of type `string`, that has no return value, since the function has been declared to have a return type of `void`.

Even if you return anything inside a callback, TypeScript **won't** throw a compilation error, instead, it will ignore it.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643804386185/xmyJJbryx.png align="left")

### DECLARE `Function` TYPE INSIDE AN `object`:

Earlier, we discussed the concept of an `object` type, which can hold a collection of different types. You can assign a `function` type to any of its keys.

#### GENERAL SYNTAX:

Take a look at the following code:

```typescript
const person: {
  name: string;
  age: number;
  sayHi(): void;
} = {
  name: "Max",
  age: 30,
  sayHi: () => {
    console.log("Hi");
  },
};
```

In the above code, we have a `person` object with a key named `say`, and it is a `function` that returns nothing.

The following is a `general` way of defining a function type. The other way to declare a function in an object is with the `property syntax`.

#### PROPERTY SYNTAX:

The `sayHi` key in the above example can be declared in `property syntax`, which is more commonly used and readable.

```typescript
const person: {
  name: string;
  age: number;
  sayHi: () => void;
} = {
  name: "Max",
  age: 30,
  sayHi: () => {
    console.log("Hi");
  },
};
```

The logic remains the same but this is a more readable and preferred format of assigning a function type.

## `unknown` TYPE:

`unknown` is not commonly used but it can be helpful to be aware of it.

### WHY USE `unknown` INSTEAD OF `any`:

`unknown` and `any` are similar to some extent but `unknown` is a bit more restrictive than `any`. To understand this take a look at the following code:

```ts
let userInput: unknown;
let userName: string;

userInput = 5;
userInput = "John";
```

In the above code, we are having `userInput` which is having types as `unknown` and `userName` with type `string`

Now, you can assign any value to the variable with the type `unknown`. So you won't get any compilation errors for assigning `5` and `"John"` to variable `userInput`.

But what happens if you try to assign `userInput` to `userName`?

```typescript
let userInput: unknown;
let userName: string;

userInput = 5;
userInput = "Max";

userName = userInput; // This line will throw an error
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643805312622/vmPa8Hy24.png align="left")

It says `Type 'unknown' is not assignable to type 'string` even though `string` has already been assigned one line before.

Since the `unknown` type can only be assigned to `any` type and the `unknown` type itself, it can never be assigned to another type.

### USE TYPE GUARDS TO AVOID ERRORS:

Adding type guards to the above code will allow it to work, as we saw in previous blogs.

```typescript
let userInput: unknown;
let userName: string;

userInput = 5;
userInput = "Max";

if (typeof userInput === "string") {
  userName = userInput;
}
```

In the above code, we are only assigning `userInput` to `userName` only if userInput has a `string` type value.

### DIFFERENCE BETWEEN `unknown` AND `any`:

What happens when you change the type of `userInput` from `unknown` to `any`?

```typescript
let userInput: any;
let userName: string;

userInput = 5;
userInput = "Max";

userName = userInput; // compile without an error
```

The main difference between `unknown` and `any` is that `unknown` is much less permissive. We must perform some form of checking before performing most operations on values of type `unknown`, but we do not have to perform any checks before performing operations on values of type `any`.

## `never` TYPE:

As the type name suggests, `never` refers to a function that will never return a value, not even an `undefined` or a `null` value.

### DIFFERENCE BETWEEN `never` AND `void`:

* The main difference between `never` and `void` is that `void` simply returns undefined if you try to access the return value from a function with `void` return type.
    
* However, the function that returns `never` will cause the **code to crash**, and the code would not be executed further.
    

### EXAMPLE 1 - FUNCTION THAT THROWS AN ERROR:

Generally, when we throw an error from any function, its return type is inferred to be `never`. Let's take a look at the following function:

```typescript
const generateError = (message: string, code: number): never => {
  throw {
    message,
    code,
  };
};

const returnedValue = generateError("Something went wrong!", 500);
console.log(returnedValue);
```

We are throwing an error whenever we call the above function. This is what we see in the console:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1644043010469/lLA5PQ6e5.png align="left")

We got the error we threw, but we didn't get any output from `console.log(returnedValue)`, not even `undefined`. It indicates that a function with a return type never caused the script to crash.

### EXAMPLE 2 - INFINITE LOOP:

Another type of function that returns `never` is the one with an infinite while loop.

```typescript
const infiniteLoop = () => {
  while (true) {}
};

const returnedValue = infiniteLoop();
console.log(returnedValue);
```

In the above function, the `infiniteLoop` the function runs continuously, which breaks the script. If you hover over the `infiniteLoop` function, you'll see that TypeScript has inferred the return type as `never`.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1644043297344/iCt190EwN.png align="left")

## CONCLUSION:

* In TypeScript, functions are the building blocks of applications. In this article, we learned how to build type-safe functions using TypeScript, different types of annotations, how to use functions as types, and the concept of `unknown` and `never` types.
    
* Having this knowledge will allow for more type-safe and easy-to-maintain functions throughout your code.
    

Make sure to subscribe to our newsletter on [***https://blog.wajeshubham.in***](https://blog.wajeshubham.in) and never miss any upcoming articles related to TypeScript and programming just like this one.

I hope this post will help you in your journey. Keep learning!

My [***Website***](https://wajeshubham.in), connect with me on [***LinkedIn***](https://www.linkedin.com/in/shubham-waje/) and [***GitHub***](https://github.com/wajeshubham).
