Functions in TypeScript

Exploring Functions in TypeScript

Functions in TypeScript

Welcome back to our TypeScript series! Today, we'll explore functions, one of the most fundamental building blocks in any programming language. We’ll cover function types, optional and default parameters, rest parameters, and function overloading.

1. Function Types and Signatures

Functions in TypeScript can be typed to ensure they receive the correct arguments and return the expected type.

Function Declaration

function add(x: number, y: number): number {
  return x + y;
}

let sum: number = add(2, 3); // 5

In this example, the add function takes two parameters of type number and returns a number.

Function Expression

let multiply: (x: number, y: number) => number = function (x: number, y: number): number {
  return x * y;
};

let product: number = multiply(2, 3); // 6

Here, the multiply variable is assigned a function that matches the specified function type.

2. Optional and Default Parameters

Optional Parameters

Parameters can be made optional by adding a question mark (?) after the parameter name. Optional parameters must come after required parameters.

function greet(name: string, greeting?: string): string {
  return `${greeting || "Hello"}, ${name}!`;
}

let greeting1: string = greet("Alice"); // "Hello, Alice!"
let greeting2: string = greet("Alice", "Hi"); // "Hi, Alice!"

Default Parameters

Default parameters have a default value if no value is provided. They can come before or after required parameters.

function greet(name: string, greeting: string = "Hello"): string {
  return `${greeting}, ${name}!`;
}

let greeting3: string = greet("Bob"); // "Hello, Bob!"
let greeting4: string = greet("Bob", "Hi"); // "Hi, Bob!"

3. Rest Parameters

Rest parameters allow a function to accept an indefinite number of arguments as an array.

function sumAll(...numbers: number[]): number {
  return numbers.reduce((acc, curr) => acc + curr, 0);
}

let total: number = sumAll(1, 2, 3, 4); // 10

The ...numbers syntax means sumAll can accept any number of arguments, which are treated as an array inside the function.

4. Function Overloading

Function overloading allows you to define multiple function signatures for a single function. This is useful when a function can handle different types or numbers of parameters.

  1. Function overloading is a feature in programming languages that allows multiple functions to have the same name but different parameters. These variations can have different types or numbers of parameters, enabling the function to perform different tasks based on the input provided. This helps in making the code more readable and manageable by using the same function name for similar operations
function callMe(phone: number): void;
function callMe(phone: string): void;
function callMe(phone: number | string): void {
  if (typeof phone === "number") {
    console.log(`Calling number: ${phone}`);
  } else {
    console.log(`Calling string: ${phone}`);
  }
}

callMe(1234567890); // "Calling number: 1234567890"
callMe("123-456-7890"); // "Calling string: 123-456-7890"

In this example, callMe is overloaded to accept either a number or a string.

5. Arrow Functions

Arrow functions provide a shorter syntax for writing functions and lexically bind the this value.

let add = (x: number, y: number): number => x + y;

let sum: number = add(5, 3); // 8

Arrow functions are particularly useful for concise one-liners and callbacks.

  1. A callback is a function that is passed as an argument to another function and is executed after some operation or event is completed. Callbacks are commonly used in asynchronous programming to handle tasks that take time, such as reading files, making API calls, or waiting for user input.

6. this in Functions

The this context in functions can be tricky. Arrow functions do not have their own this context; instead, they inherit this from the enclosing scope.

—>(this basically means calling context)

Scope in programming refers to the context or region within a program where a variable or function is accessible. There are mainly two types of scope:

  1. Global Scope: Variables or functions declared in the global scope are accessible from anywhere in the program.

  2. Local Scope: Variables or functions declared within a function or block are only accessible within that function or block.

Regular Function

class Person {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  greet() {
    setTimeout(function() {
      console.log(`Hello, my name is ${this.name}`); // `this` is undefined here
    }, 1000);
  }
}

let person = new Person("Alice");
person.greet(); // Error: `this` is undefined

Arrow Function

class Person {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  greet() {
    setTimeout(() => {
      console.log(`Hello, my name is ${this.name}`); // `this` refers to the Person instance
    }, 1000);
  }
}

let person = new Person("Alice");
person.greet(); // "Hello, my name is Alice"

Example Code

Here’s an example that utilizes various aspects of functions in TypeScript:

function createUser(name: string, age: number, ...skills: string[]): { name: string; age: number; skills: string[] } {
  return {
    name,
    age,
    skills
  };
}

let user = createUser("Alice", 25, "TypeScript", "JavaScript", "React");

console.log(user);
// { name: 'Alice', age: 25, skills: [ 'TypeScript', 'JavaScript', 'React' ] }

Summary

Today, we covered functions in TypeScript, including function types, optional and default parameters, rest parameters, function overloading, arrow functions, and the this context. Functions are essential for structuring your code and making it reusable and modular.

Next time, we’ll dive into interfaces in TypeScript. Stay tuned!