# How to Define a TypeScript Function Type Callback That Accepts Any Signature Without Using `any`

> Define flexible TypeScript function types that accept any signature without using any. Learn to create generic callback types for enhanced code safety and reusability. Explore practical examples.

- Repository: [Microsoft/TypeScript](https://github.com/microsoft/typescript)
- Tags: how-to-guide
- Published: 2026-02-11

---

**Use a generic function type with `unknown` constraints:** `type Callback<Args extends readonly unknown[] = unknown[], R = unknown> = (...args: Args) => R;`

The `microsoft/TypeScript` repository demonstrates that when you need a flexible **typescript function type callback**, you should avoid the universal `(...args: any[]) => any` pattern. Instead, generic type parameters preserve type safety while allowing any function signature, letting the compiler infer argument and return types at the call site.

## Why Universal Function Types Break Type Safety

A naïve approach to accepting "any function" uses the type `(...args: any[]) => any`. This creates a **universal type** that disables type checking for both parameters and return values. Once you annotate a callback with this type, the compiler can no longer verify that arguments passed to the function match its expected signature, nor can it infer what the function returns. This silently erases type information and allows invalid operations at runtime.

## The Generic Callback Pattern

The robust solution defines a **generic callback type** using `unknown` instead of `any`. This pattern captures the argument list and return type as type parameters, maintaining type awareness without restricting the specific shape of the function.

### Basic Generic Implementation

Define the type with two parameters: `Args` for the tuple of argument types and `R` for the return type:

```typescript
type Callback<Args extends readonly unknown[] = unknown[], R = unknown> = (
    ...args: Args
) => R;

```

This definition uses `unknown` with constraints to prevent the type from becoming a catch-all `any`. The defaults (`unknown[]` and `unknown`) allow the type to represent any function when specific parameters are not provided, while concrete instantiations preserve full type information.

### Usage in Higher-Order Functions

You can use this pattern in higher-order functions that invoke callbacks safely:

```typescript
function invoke<T extends unknown[], R>(cb: Callback<T, R>, ...args: T): R {
    return cb(...args);
}

// Example: explicit typing
const ok: Callback<[string, number], boolean> = (s, n) => s.length > n;
const result = invoke(ok, "hello", 2); // result is inferred as boolean

```

The compiler validates that `"hello"` and `2` match the `[string, number]` tuple and that `result` receives the `boolean` return type.

## How TypeScript Implements This Internally

The TypeScript compiler itself distinguishes between internal utility types and public-facing generics. According to the source code in [`src/compiler/core.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/core.ts) at line 1934, the repository defines an internal `AnyFunction` type for compiler use:

```typescript
// Located at src/compiler/core.ts#L1934
type AnyFunction = (...args: never[]) => void;

```

This internal type serves as a placeholder for "any callable" within the compiler's implementation details. However, for public APIs and user code, the TypeScript codebase favors explicit generic patterns like the `Callback` type shown above, which preserve type relationships rather than discarding them.

## Complete Code Examples

### Inferring Types Automatically

When you wrap a function using generics, TypeScript can infer the specific signature from the supplied callback:

```typescript
function wrap<T extends unknown[], R>(cb: Callback<T, R>) {
    return (...args: T) => cb(...args);
}

const add = (a: number, b: number) => a + b;
const safeAdd = wrap(add); // safeAdd: (a: number, b: number) => number

```

### Mapping Values with Callbacks

Generic callbacks work seamlessly with utility functions that transform data:

```typescript
function mapCallback<A, B>(cb: Callback<[A], B>, value: A): B {
    return cb(value);
}

const toString: Callback<[number], string> = n => n.toString();
const str = mapCallback(toString, 42); // "42"

```

### Comparison with Non-Generic Alternatives

| Type | Safety Level | Use Case |
|------|--------------|----------|
| `(...args: any[]) => any` | None (universal) | Avoid in public APIs |
| `(...args: unknown[]) => unknown` | Low | When you only need "callable" verification |
| `Callback<T, R>` | High | When parameter and return types must be preserved |

## Summary

- **Avoid** `(...args: any[]) => any` for callback types because it creates a universal type that disables type checking.
- **Use** a generic `Callback<Args, R>` definition with `unknown` constraints to accept any function signature while preserving type information.
- **Reference** [`src/compiler/core.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/core.ts) line 1934 to see how TypeScript internally uses restricted function types for compiler utilities.
- **Leverage** type inference with higher-order functions like `invoke`, `mapCallback`, or `wrap` to maintain strict type safety without verbose annotations.

## Frequently Asked Questions

### What is the difference between `(...args: any[]) => any` and a generic callback type?

`(...args: any[]) => any` is a universal type that tells TypeScript to ignore type checking for both arguments and return values. A generic callback type like `Callback<T, R>` captures the specific argument tuple `T` and return type `R`, allowing the compiler to verify that calls match the function signature and to infer the result type correctly.

### Why should I avoid using `any` for function callbacks in TypeScript?

Using `any` for callbacks disables the compiler's ability to catch mismatched arguments or incorrect return value usage. It also prevents IntelliSense and autocomplete features from working correctly in IDEs. The `unknown` type with generics provides the same flexibility without sacrificing type safety.

### How does TypeScript's own compiler define internal function types?

According to the `microsoft/TypeScript` source code, the internal `AnyFunction` type is defined in [`src/compiler/core.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/core.ts) at line 1934 as `(...args: never[]) => void`. This internal type is restricted to compiler-specific use cases, while the codebase encourages public APIs to use more expressive generic patterns that retain type information.

### Can I constrain the return type to `void` for callback functions?

Yes, you can create a specialized version by setting `R = void` or constraining the generic: `type VoidCallback<Args extends unknown[]> = Callback<Args, void>`. This ensures the callback does not return a usable value, though TypeScript will still allow functions that return values to be assigned to it (it only checks that you don't use the return value).