Skip to main content

Functions

Function Annotations

In TypeScript, function annotations are a way to explicitly define the types of a function’s parameters and its return value.

function functionName(param1: Type, param2: Type, ...): ReturnType {
// function body
}
  • param: Type → Type annotation for each parameter.
  • : ReturnType → Type annotation for the value the function returns.

Why use Function Annotations?

  • Type safety → prevents passing wrong argument types.
  • Code readability → makes functions self-documenting.
  • Better tooling → helps IDEs provide autocomplete & hints.

Function Returning never

function throwError(msg: string): never {
throw new Error(msg);
}
  • never indicates that the function never successfully returns (it either throws an error or runs forever).
  • void means return nothing, never means thow an error or runs forever.

Optional & Default Parameters

function welcomeUser(
name: string,
age?: number,
country: string = "Unknown"
): string {
return `Hello ${name}, Age: ${age ?? "Not provided"}, Country: ${country}`;
}

console.log(welcomeUser("Alice"));
// Hello Alice, Age: Not provided, Country: Unknown
console.log(welcomeUser("Bob", 30, "USA"));
// Hello Bob, Age: 30, Country: USA
  • age? → optional parameter (Must always come after required parameters, If not provided, it will be undefined).
  • country = "Unknown" → default parameter. Unlike optional parameters, default parameters don’t have to be at the end.
function greet(name: string = "Guest", age: number): string {
return `Hello, my name is ${name} and I am ${age} years old.`;
}

console.log(greet(undefined, 25)); // ✅ "Hello, my name is Guest and I am 25 years old."

If you want to use the default for name, you must explicitly pass undefined since age is required.

Recommended order: required → default → optional

Difference Between optional (?) vs. | undefined

These look similar but are not exactly the same.

type A = { age?: number }; // optional property
type B = { age: number | undefined }; // required property but can hold undefined
  • age?: number → property may be missing entirely.
  • age: number | undefined → property must exist, but value may be undefined.

Function Type Alias

type MathOperation = (a: number, b: number) => number;

const multiply: MathOperation = (x, y) => x * y;

console.log(multiply(4, 5)); // 20

This defines a reusable function type.

Rest Parameter

function functionName(...paramName: Type[]): ReturnType {
// function body
}
  • ...paramName → rest parameter, collects all remaining arguments into an array.
  • Type[] → type annotation (array of a specific type).

Pass value with rest parameter not reference.

Differences between Rest Parameters and Spread Operator

FeatureRest Parameters (...)Spread Operator (...)
Where used?Function definitionFunction call, array/object creation
What it does?Collects multiple arguments into an arrayExpands array/object into individual elements
Data DirectionMany → One (arguments → array)One → Many (array → arguments/elements)
Examplefunction sum(...nums: number[]) {}sum(...[1,2,3])

Function Overloading

In TypeScript, function overloading allows you to define multiple function signatures (different parameter types/number of parameters) for the same function name.

  • It’s a way to describe different call patterns for one function.
  • At runtime, there’s still only one function implementation, but TypeScript uses the overload signatures to check types at compile time.

Syntax

// Overload Signatures
function functionName(param1: TypeA): ReturnTypeA;
function functionName(param1: TypeB, param2: TypeC): ReturnTypeB;

// Implementation Signature
function functionName(param1: any, param2?: any): any {
// single implementation
}
  1. You write multiple overload signatures (only declarations, no body).
  2. You provide one implementation that handles all cases.
  3. The implementation must be compatible with all overload signatures.

Function Overload by Parameter Type

// Overload signatures
function getLength(value: string): number;
function getLength(value: any[]): number;

// Implementation
function getLength(value: string | any[]): number {
return value.length;
}

console.log(getLength("Hello")); // 5
console.log(getLength([1, 2, 3])); // 3

this in functions

  • In JavaScript, this refers to the context in which a function is called.
  • In TypeScript, we can annotate the type of this inside a function for type checking.
  • This prevents bugs where this is used incorrectly.

Declaring this Type in Functions

In TypeScript, the first parameter of a function can be a special this parameter (not counted as a real argument).

function functionName(this: Type, param1: Type, param2: Type): ReturnType {
// function body
}
  • this: Type → defines the expected type of this.
  • It’s only used by TypeScript’s type checker (not compiled into JavaScript).

Incorrect this Usage (Type Safety)

type Person = {
name: string;
greet(this: Person): void;
};

const person: Person = {
name: "Alice",
greet(this: Person) {
console.log(`Hello, ${this.name}`);
},
};

const greetFn = person.greet;
// greetFn(); // ❌ Error in TypeScript: 'this' has type 'void' here
  • When greet is extracted into greetFn, this becomes undefined.
  • TypeScript prevents calling it without a proper this.

Use .bind to preserve this

const greetFn = person.greet.bind(person);
greetFn(); // ✅ Hello, Alice
  • .bind(person) creates a new function where this is always person.