Introduction
If you’ve dipped your toes into TypeScript, chances are you’ve already met functions, those little blocks of reusable code that make our lives a whole lot easier.
In this article, you’ll learn:
- What is a Function?
- Function Signature
- Function Parameters and Return Types
- Optional Parameters
- Default Parameters
- Return Types
- Function Types and Signatures
- Named vs Anonymous Functions vs Arrow Functions
- Function Overloads
- Functions as Values (Passing Functions as Parameters)
What is a Function?
A function is a block of code that performs a task and can be reused.
Here’s a simple example:
function greet(name: string): void {
console.log(`Hello, ${name}!`);
}
- name: string: this is a parameter with type
- : void is the return type (in this case, the function doesn’t return anything)
You can call it like this:
greet("Alex"); // Output: Hello, Alex!
Function Signature
A function signature defines the shape of a function, what parameters it takes, and what it returns, without including the actual implementation (i.e., the function body).
So basically it includes,
- The name of the function (if defined),
- The parameter types (and optionally names),
- The return type.
// Example
function add(a: number, b: number): number {
return a + b;
}
// Function Signature:
(a: number, b: number) => number
Function Parameters and Return Types
TypeScript lets you be specific about:
- What a function takes in (parameters): The function add takes x and y (typed numbers) as parameters
- What it gives back (return type): The function add returns a number
function add(x: number, y: number): number {
return x + y;
}
Optional Parameters
Sometimes, not every argument is required:
function log(message: string, userId?: number): void {
console.log(`Message: ${message}`);
if (userId) {
console.log(`User ID: ${userId}`);
}
}
So, how do you call it?
log("How you doin?"); // Message: How you doin?
log("How you doin?", 2);
// Message: How you doin?
// User ID: 2
Tip: Optional parameters (?) should always come after required ones.
Default Parameters
You can also set default values: while doing so, make sure to take the question mark (?) out and assign a value, like 10 in this example
function log(message: string, userId : number = 10): void {
...
}
log("How you doin?");
// Message: How you doin?
// User ID: 10
Tip: Do use defaults for common behavior
Return Types
The following function returns a number.
function multiply(x: number, y: number): number {
return x * y;
}
Special Return Types
- void: returns nothing
- never: function doesn’t return at all (e.g., throws an error)
- unknown: return type is intentionally unspecified
1. void: returns nothing
It's a function that just does its job and doesn’t give you anything back.
function sendNotification(message: string): void {
console.log(`Notification: ${message}`);
}
sendNotification("10k steps complete!");
2. never: function doesn’t return at all but throws an error)
This function always throws an error and never returns anything normally.
function raiseAlarm(): never {
throw new Error("Emergency! Fire alarm triggered!");
}
![never]()
3. unknown: return type is intentionally unspecified
where void returns nothing, unknown returns something, but we don’t know what, so use it when you want a function to return a value, but you don’t yet know its type, or you want to force the user to check the type before using it.
It's like a gift, you're gonna get something, but you just don't know what.
function getMeGift(): unknown {
return Math.random() > 0.5 ? 42 : "hello";
}
getMeGift();
// console.log(value.toUpperCase()); Error!
// TypeScript won’t let you use `value` until you check its type:
if (typeof value === "string") {
console.log(value.toUpperCase()); // Safe
}
Function Types and Signatures
You can define what a function should look like using function types.
let calculator: (x: number, y: number) => number;
calculator = function (a, b) {
return a + b;
};
You can also make this reusable using a type alias:
type Subtract = (a: number, b: number) => number;
const subtract: Subtract = (a, b) => a - b;
Named vs Anonymous Functions vs Arrow Functions
1. Named
These are functions that have a name, like add in this example, and can be referenced by that name elsewhere in your code.
function add(a: number, b: number): number {
return a + b;
}
2. Anonymous
These are functions without a name. They're often used as function expressions, callbacks, or passed as arguments.
const multiply = function(a: number, b: number): number {
return a * b;
};
- This is an anonymous function, stored in a variable called multiply.
- The function itself has no name, but you can still use it via the variable.
3. Arrow
Arrow functions are short, concise
//Example 1
const subtract = (a: number, b: number): number => a - b;
//Example 2
const square = (n: number): number => n * n;
Great for inline stuff, especially:
[1, 2, 3].map(n => n * 2);
Function Overloads
Function overloading means you can define multiple versions of the same function, with different parameter types or counts, to handle different input scenarios while keeping one unified implementation behind the scenes.
Why Use Overloading?
Overloading is useful when:
- A function should behave differently based on input types.
- You want to avoid messy if-else or typeof logic scattered in code.
Example
Suppose you want a combined function that can:
- Add two numbers (e.g. combine(2, 3) → 5)
- Concatenate two strings (e.g. combine("2", "3") → "23")
function combine(a: number, b: number): number;
function combine(a: string, b: string): string;
function combine(a: any, b: any): any {
return a + b;
}
combine(5, 10); // Returns 15 (number)
combine("5", "10"); // Returns "510" (string)
combine(5, "10"); // Error: No overload matches this call
This function works with either two numbers or two strings.
- It adds if both are numbers
- It concatenates if both are strings
- Notice: combine(5, "10") will give a TypeScript error, which is good! This gives us type safety, catching invalid usage early.
Functions as Values (Passing Functions as Parameters)
Functions in TypeScript are first-class values. You can pass them around just like numbers or strings.
Step 1: Create Discount Functions
function flatDiscount(price: number): number {
return price - 10;
}
function percentDiscount(price: number): number {
return price * 0.9; // 10% off
}
Step 2: Pass Function as Parameter
function calculateTotal(price: number, discountFn: (price: number) => number): number {
return discountFn(price);
}
const total1 = calculateTotal(100, flatDiscount); // 90
const total2 = calculateTotal(100, percentDiscount); // 90
Step 3: Simplify with Custom Function Type
type DiscountStrategy = (price: number) => number;
function calculateTotal(price: number, discountFn: DiscountStrategy): number {
return discountFn(price);
}
Conclusion
In TypeScript, a function doesn't seem to be just a chunk of logic. It’s a well-typed contract. From basic signatures to optional and default parameters, return types, and function overloads, you’ve seen most of it.
We covered function expressions, named, anonymous, and arrow, and went deeper into treating functions as values. Passing logic as arguments? Creating reusable strategies with custom types? Yup, that’s the good stuff.
Bottom line: TypeScript functions don’t just run, they declare, demand, and deliver.
So yes, sir, this is a TypeScript function… and it means business.