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);
}
neverindicates that the function never successfully returns (it either throws an error or runs forever).voidmeans return nothing,nevermeans 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 beundefined).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 beundefined.
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
| Feature | Rest Parameters (...) | Spread Operator (...) |
|---|---|---|
| Where used? | Function definition | Function call, array/object creation |
| What it does? | Collects multiple arguments into an array | Expands array/object into individual elements |
| Data Direction | Many → One (arguments → array) | One → Many (array → arguments/elements) |
| Example | function 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
}
- You write multiple overload signatures (only declarations, no body).
- You provide one implementation that handles all cases.
- 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,
thisrefers to the context in which a function is called. - In TypeScript, we can annotate the type of
thisinside a function for type checking. - This prevents bugs where
thisis 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 ofthis.- 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
greetis extracted intogreetFn,thisbecomesundefined. - 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 wherethisis always person.