This episode covers function typing in depth: parameter and return type annotations, optional parameters, default values, rest parameters, and function overloads. You'll also see when to write the return type explicitly.

Functions are the main unit of work in a TypeScript application. In earlier episodes, functions only appeared as short examples. Episode 7 focuses fully on function typing: how to annotate parameters, set the return value, and declare a contract that forces callers to pass the right arguments.
Without good typing, a function is just a machine that accepts anything and returns anything. With types, a function becomes a documented component: the function name tells you what it does, and its signature tells you how to use it safely.
You'll learn optional parameters marked with a question mark, default values, rest parameters for an unlimited number of arguments, and function overloads for functions that serve several calling forms at once.
The most explicit way to write a function:
function tambah(a: number, b: number): number {
return a + b;
}
const kali = (a: number, b: number): number => a * b;The declaration function tambah(a: number, b: number): number forces every call to pass two number arguments and guarantees the result is also a number. TypeScript raises an error when arguments are missing, excessive, or of the wrong type. This annotation works equally well for function declarations and arrow functions.
Often the return type can be inferred on its own:
function gabung(nama: string, tahun: number) {
return `${nama} tahun ${tahun}`;
}
const hasil = gabung("Bumi", 2026);TypeScript infers the return value of gabung as string from the template expression. Letting inference do its job keeps the code concise. An explicit return type is still useful for recursive functions or when you want to prevent accidental changes to the shape of the result.
Arguments that may be omitted are marked with a question mark:
function sapa(nama: string, sapaan?: string): string {
return sapaan ? `${sapaan}, ${nama}` : `Halo, ${nama}`;
}
sapa("Budi");
sapa("Budi", "Selamat pagi");The sapaan? parameter may be omitted. Inside the function, its value has the type string | undefined, so it needs a check before use. Optional parameters must come after required parameters so calls remain sensible.
Default values replace the need for optional parameters in many cases:
function diskon(harga: number, persen: number = 10): number {
return harga - (harga * persen) / 100;
}
console.log(diskon(100_000));
console.log(diskon(100_000, 25));The persen parameter gets the value 10 when the caller doesn't provide one. Unlike optional parameters, a parameter with a default needs no extra check because its value is always present.
A rest parameter collects the remaining arguments in any quantity:
function total(...angka: number[]): number {
return angka.reduce((acc, n) => acc + n, 0);
}
console.log(total(1, 2, 3, 4));The ...angka parameter gathers all extra arguments into a number array. A call can pass one, two, or ten numbers without changing the declaration. A rest parameter is always an array type and must be the last parameter.
A single function sometimes serves several different argument combinations. Overloads declare each combination separately:
function format(tanggal: Date): string;
function format(epoch: number): string;
function format(sumber: Date | number): string {
return sumber instanceof Date
? sumber.toISOString()
: new Date(sumber).toISOString();
}The first two lines are the overload signatures callers see, while the third line is the implementation that bridges them all. Callers get clarity about the valid argument shapes, while the implementation handles both cases with a union. Overloads are most useful when a function accepts inputs with very different shapes.
Warning
Overloads add complexity. For small differences like one extra parameter, just use an optional parameter or a default. Reserve overloads for combinations whose argument shapes genuinely differ.
Episode 7 makes your functions safe from incorrect calls. With parameter annotations, return types, optional parameters, defaults, rest parameters, and overloads, you can state precisely what a function needs and what it will return.
Key takeaways:
string | undefined inside the function.In the next episode 8 we'll discuss generics and parametric types — a tool for writing functions and structures that work for many types without losing type guarantees.