Functions in TypeScript: Typing Parameters and Return Values

Learn how to type functions in TypeScript: parameter types, return types, optional, default, and rest parameters, function-type expressions, void, and a peek at overloads.

Published September 20, 20269 min readBy ACY Partner Indonesia
Functions in TypeScript cover with a typed function signature
300 × 250Ad Space AvailablePlace your ad here

A function is a small machine: you feed it some values, it does a bit of work, and it hands you something back. In plain JavaScript, nobody checks what you feed in or what comes out. You could call a function meant for numbers with a string, and you wouldn’t find out until the program misbehaves at runtime. TypeScript changes that. By adding types to a function’s inputs and output, you turn the function into a contract that the editor and the compiler can enforce before your code ever runs.

If you’ve already met functions in regular JavaScript, this article builds directly on that. The shapes are the same; we’re just labelling the slots. If you’d like a refresher on how functions behave in the first place, the JavaScript side is here: JavaScript Functions.

Typing the parameters

A parameter is a value a function expects to receive. In TypeScript you write the expected type right after the parameter name, separated by a colon.

function greet(name: string) {
  return "Hello, " + name;
}

greet("Jane");   // fine
greet(42);       // error: number is not assignable to string

That second call never makes it past the compiler. TypeScript reads name: string as a promise: this slot only accepts text. The moment you pass a number, the editor underlines it in red and tells you exactly what’s wrong. You catch the mistake while typing, not when a user clicks a button in production.

Each parameter is typed independently, so a function can mix types freely.

function repeat(text: string, times: number) {
  return text.repeat(times);
}

repeat("ab", 3); // "ababab"

If you forget to annotate a parameter, TypeScript falls back to a special type called any, which means “anything goes, stop checking.” That’s usually not what you want, because it switches the safety off for that value. Many projects turn on a setting that flags un-annotated parameters so you don’t lose protection by accident.

Typing the return value

The return type describes what the function gives back. You write it after the parameter list, again with a colon.

function add(a: number, b: number): number {
  return a + b;
}

Here : number after the parentheses says “this function returns a number.” If the body ever returned something else, TypeScript would complain.

You don’t always have to write the return type yourself. TypeScript is good at inferring it — looking at the body and figuring out the answer. In add, it already knows two numbers added together make a number, so the annotation is optional. Still, writing it down has a real benefit: it documents your intent and catches you if the body drifts away from what you promised.

When to write return types by hand

For small internal helpers, let inference do the work. For public functions that other parts of your app rely on, write the return type explicitly. It acts as a guardrail: if you accidentally change what the function returns, the error appears in the function itself, not in some distant file that called it.

Optional and default parameters

Sometimes an argument isn’t always needed. Mark a parameter optional with a question mark after its name. An optional parameter might be missing, so its type automatically includes undefined.

function createUser(name: string, nickname?: string) {
  if (nickname) {
    return name + " (" + nickname + ")";
  }
  return name;
}

createUser("Jane Doe");            // fine, nickname omitted
createUser("John Doe", "Johnny");  // fine, nickname given

A close cousin is the default parameter: a value used when the caller leaves the argument out. You don’t even need to annotate it, because TypeScript reads the type from the default.

function connect(host: string, port = 8080) {
  return `${host}:${port}`;
}

connect("acy-partner.com");        // "acy-partner.com:8080"
connect("acy-partner.com", 3000);  // "acy-partner.com:3000"

Because port = 8080 is a number, port is typed as number without you saying so. One important rule: optional and default parameters belong at the end of the list. A required parameter can’t sit after an optional one, because the caller would have no way to skip the optional one cleanly.

Rest parameters

What if you don’t know how many arguments will arrive? A rest parameter collects all the leftover arguments into a single array. You write three dots before the name, and you type it as an array.

function sum(...numbers: number[]): number {
  let total = 0;
  for (const n of numbers) {
    total += n;
  }
  return total;
}

sum(1, 2, 3);       // 6
sum(10, 20, 30, 40); // 100

Because numbers is typed as number[] (an array of numbers), TypeScript checks every argument you pass. Slip a string in there and you’ll get an error pointing straight at it. A rest parameter is always the last parameter, since it sweeps up everything that’s left.

Function-type expressions

So far we’ve typed the insides of a function. But functions are values too — you can store them in variables and pass them to other functions. To describe the shape of a function as a value, TypeScript uses a function-type expression. It looks like an arrow:

(x: number) => string

Read it as: “a function that takes one number and returns a string.” Note the arrow => here is part of a type, describing a function — it’s not the same as the arrow in an arrow function, even though they look alike.

This is most useful when a function accepts another function (a callback). You can spell out exactly what that callback must look like.

function transform(value: number, fn: (x: number) => string): string {
  return fn(value);
}

transform(42, (n) => "Number: " + n); // "Number: 42"

The parameter fn is required to be a function from number to string. Pass a function with the wrong shape and TypeScript refuses it before the program runs.

Piece Meaning
(x: number) the function takes one number parameter
=> “returns”
string the type it returns

You can also name these shapes with a type alias to keep signatures readable:

type Formatter = (x: number) => string;

function transform(value: number, fn: Formatter): string {
  return fn(value);
}

The void return type

Some functions don’t return a useful value at all — they just do something, like logging a message or saving data. Their return type is void, which means “this function returns nothing meaningful.”

function logMessage(message: string): void {
  console.log(message);
}

void is your way of telling readers (and the compiler) that the result isn’t meant to be used. If you try to assign the outcome of a void function to a variable expecting a real value, TypeScript will warn you. It’s the difference between a function that answers a question and a function that performs an action.

A brief look at overloads

Occasionally a single function needs to behave differently depending on what it receives. Overloads let you declare several call signatures for one function, so callers get the right type for each case.

function parseInput(value: string): string[];
function parseInput(value: number): number;
function parseInput(value: string | number): string[] | number {
  if (typeof value === "string") {
    return value.split(",");
  }
  return value * 2;
}

const a = parseInput("a,b,c"); // typed as string[]
const b = parseInput(10);      // typed as number

The first two lines are the overload signatures — the versions callers see. The third line is the real implementation, which has to handle every case but stays hidden from callers. Overloads are an advanced tool, and most of the time a single clear signature (or a union type) is enough. Reach for them only when a function genuinely changes its return type based on its input.

Overloads are a last resort

Overloads add complexity quickly. Before writing them, ask whether a simpler design — splitting into two named functions, or accepting one consistent type — would serve readers better. Clear beats clever.

How typed functions catch call-site mistakes

The real payoff of all this typing shows up at the call site — the place where you actually use the function. Because TypeScript knows the exact shape a function expects, it checks every call against that shape.

add(a: number, b: number): number

   add(2, 3)        ✓  two numbers, all good
   add(2, "3")      ✗  "3" is a string, not a number
   add(2)           ✗  missing the second argument
   add(2, 3, 4)     ✗  one argument too many

Every one of those wrong calls is flagged in your editor with a clear message, and the build refuses to proceed. In plain JavaScript, add(2, "3") would quietly produce "23" — a string instead of a number — and you might not notice until something downstream breaks in a confusing way. Typed functions move that discovery from runtime, where bugs are expensive and hard to trace, to edit time, where they’re cheap and obvious.

Recap

Functions in TypeScript are ordinary JavaScript functions with their slots clearly labelled. Here’s what to carry forward:

  • Parameter types (name: string) say what each input must be.
  • Return types (: number) say what comes back; TypeScript can often infer this, but writing it for public functions is a useful guardrail.
  • Optional (nickname?) and default (port = 8080) parameters handle arguments that aren’t always supplied — keep them at the end.
  • Rest parameters (...numbers: number[]) collect any number of leftover arguments into a typed array.
  • Function-type expressions ((x: number) => string) describe a function used as a value, which is perfect for callbacks.
  • void marks functions that do something rather than return something.
  • Overloads let one function present different signatures — powerful, but save them for when you truly need them.

Get comfortable typing your functions and you’ll feel the difference immediately: fewer surprises, clearer code, and an editor that catches your mistakes the moment you make them. If you want to revisit how functions work underneath all these labels, the JavaScript foundations are a good next stop: JavaScript Functions.

Tags:typescriptfunctionstypesfrontendparametersreturn-types
728 × 90Ad Space AvailablePlace your ad here

Related Articles

See All Articles

You Might Also Like

Frontend best practices overview cover
Frontend / Fundamentals

Frontend Best Practices: An Overview

A friendly map of what good frontend really means — semantic HTML, clean CSS, unobtrusive JavaScript, responsive layouts, performance, and progressive enhancement, with pointers to go deeper.

Sep 20, 20268 min read
A Frontend Developer Roadmap cover with the path HTML to CSS to JavaScript
Frontend / Fundamentals

A Frontend Developer Roadmap: What to Learn, and in What Order

A calm, step-by-step learning path for beginners: HTML, CSS, JavaScript, developer tools, responsive and accessible design, a framework, TypeScript, and deployment, with the reasoning behind each step.

Sep 20, 202611 min read
Title card reading Styling and Interactivity over a dark blue ACY Partner background
Frontend / Fundamentals

How Styling and Interactivity Work

A beginner-friendly look at how CSS turns plain HTML into a designed layout, and how JavaScript adds behavior — the structure, style, behavior mental model for building web pages.

Sep 20, 20269 min read
Three front-end layers combining on one web page
Frontend / Fundamentals

How HTML, CSS, and JavaScript Work Together

A hands-on walkthrough for beginners: build one small button, give it structure with HTML, looks with CSS, and behavior with JavaScript, and watch the three layers cooperate on a real page.

Sep 20, 20268 min read
The Frontend Developer Toolkit cover with editor, browser, and CLI motifs
Frontend / Fundamentals

The Frontend Developer Toolkit

A friendly tour of the everyday tools a frontend developer relies on — code editor, browser and DevTools, terminal, version control, package managers, and a dev server — and what each one is actually for.

Sep 20, 202610 min read
Cover illustration for What Frontend Developers Do
Frontend / Fundamentals

What Frontend Developers Do: A Beginner's Guide to the Role

A clear, beginner-friendly look at what frontend developers actually do every day: turning designs into working interfaces, building reusable UI, and caring about responsiveness, accessibility, and speed.

Sep 20, 202610 min read