---
title: "TypeScript function overloading: a real-world example"
description: "TypeScript function overloading explained with a realistic, real-world example — when it beats union types and how to write overloads cleanly. The example is a hook straight out of my state-in-url library."
canonical: "https://asmyshlyaev177.dev/blog/ts-function-overloading-real-world-example"
published: "August 9, 2024"
tags: ["TypeScript"]
---

# TypeScript function overloading: a real-world example

> TypeScript function overloading explained with a realistic, real-world example — when it beats union types and how to write overloads cleanly. The example is a hook straight out of my state-in-url library.

---

Let's dive into less frequent Typescript feature - **function overloading** with a realistic example.

## Intro

Have a custom hook

```typescript
export function useUrlState<T extends JSONCompatible>(
  defaultState: T,
  searchParams?: object,
);
```

At some moment I need to add more arguments to it, possibly more in the future. Hard to remember what Nth argument is, and calling a function like `useUrlState(firstArg, null, null, fourthArg)` is ridiculous. It will be way easier to pass arguments inside an object like this:

```typescript
export function useUrlState<T extends JSONCompatible>({
  defaultState,
  searchParams,
  replace,
}: {
  defaultState: T;
  searchParams?: object;
  replace?: boolean;
});
```

I will convert the function to a new format and keep it backward compatible with the existing implementation.

## Implementation

First, need to add **overload signatures** right above function **implementation**. Overload signatures are all possible ways a function can be called, with different argument's type and quantity.

```typescript

/**
 * @deprecated Pass arguments in a object `useUrlState({ defaultState: form, searchParams })`
 *
 *  * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#api}
 */
export function useUrlState<T extends JSONCompatible>(defaultState: T, searchParams?: object): {
  state: DeepReadonly<T>,
  updateState: (value: Partial<DeepReadonly<T>>,
  updateUrl: (value?: Partial<DeepReadonly<T>>) => void,
  getState: () => DeepReadonly<T>
}
/**
 * NextJS hook. Returns `state`, `updateState`, and `updateUrl` functions
 *
 * @param {JSONCompatible<T>} [defaultState] Fallback (default) values for state
 * @param {?SearchParams<T>} [searchParams] searchParams from Next server component
 */
export function useUrlState<T extends JSONCompatible>({ defaultState, searchParams }: {
  defaultState: T, searchParams?: object, replace?: boolean
}): {
  state: DeepReadonly<T>,
  updateState: (value: Partial<DeepReadonly<T>>) => void,
  updateUrl: (value?: Partial<DeepReadonly<T>>) => void,
  getState: () => DeepReadonly<T>
} // <- notice that should implicitly define returned value
// implementation
export function useUrlState<T extends JSONCompatible>(
  defaultState: T | { defaultState: T, searchParams?: object, replace?: boolean },
  searchParams?: object,
) {
```

Tricky part is that signatures should be **compatible** with implementation, so have this `defaultState: T | { defaultState: T, searchParams?: object, replace?: boolean }`

I assume that if the first argument has a specific key, it is a new object format.

```typescript
const _defaultState = (
  "defaultState" in defaultState ? defaultState.defaultState : defaultState
) as T;
const _searchParams = (
  "defaultState" in defaultState ? defaultState.searchParams : searchParams
) as object | undefined;
const _replace = (
  "defaultState" in defaultState ? (defaultState.replace ?? true) : false
) as boolean;
```

Also, can notice that `replace` argument has default value `true` for a new format, but for old one it's `false`.

Let's see how it works.

![Result](https://asmyshlyaev177.dev/_astro/xxuva5w3786wxte3zxg4.uk8wPgLG.gif)

Notice that we have different JSDoc comments for each signature, old one marked with `@deprecated` tag.

Official docs https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads

Tnx for reading :)

Leave a comment about your experience, or if you have ideas how to do it more elegantly.

---

Author: Aleksandr Smyshliaev — <https://asmyshlyaev177.dev>
More posts: <https://asmyshlyaev177.dev/blog> · Site summary for LLMs: <https://asmyshlyaev177.dev/llms.txt>
