Tips for defining types for a function that serves as an argument and can accept any parameters and return any values

I am interested in implementing a debounce function using TypeScript. Below is the code snippet I have written:

function debounce(fn: Function, time: number): Function {
  // ...
}

However, my eslint is flagging an issue with using Function as a type. Here is the original text:

Avoid using Function as a type. The Function type can accept any function-like value. This lack of type safety when calling the function can lead to common bugs. It may also allow things like class declarations, which will throw errors at runtime if they are not called with new.

If you need the function to accept specific arguments, it's recommended to explicitly define the function shape.

This seems to be causing an issue, any suggestions?

==================== Some update ==================================

If I were to use JavaScript instead, my code would look like this:

function debounce(fn, time) {
  let timer
  return function (...args) {
    clearTimeout(timer)
    timer = setTimeout(() => fn(...args), time)
  }
}

Answer №1

After reviewing your current setup, it appears that the function returned from debounce() lacks a meaningful result. As a result, the return type of the fn parameter becomes irrelevant. In this scenario, one approach would be to transform debounce() into a generic function utilizing a type parameter A structured as a rest tuple representing the arguments for fn. The revised structure could be:

function debounce<A extends any[]>(fn: (...a: A) => void, time: number) {
    let timer: number;
    return function (...args: A) {
        clearTimeout(timer)
        timer = setTimeout(() => fn(...args), time)
    }
}

The type (...a: A) => void signifies a function type expression, indicating "a function with an argument array of type A, returning void thereby ignoring its return value".

Upon examining the type of debounce(), the structure reads as follows:

/* function debounce<A extends any[]>(
     fn: (...a: A) => void, time: number
   ): (...args: A) => void */

Therefore, it accepts a function of type (...a: A) => void and yields a function of the same nature.


To test its effectiveness, consider the following snippet:

function log(x: string) {
    console.log(x);
}

const debouncedLog = debounce(log, 1000);

debouncedLog("hello");
debouncedLog(100); // error, does not support numbers
debouncedLog("there");
// only "there" gets logged

The compiler flags debouncedLog(100) due to the mismatch between 100 and string, while other calls execute without issues.

Playground link to code

Answer №2

You might find it beneficial to explore TypeScript's utility types, particularly Parameters<Type> and ThisParameterType<Type>. These were instrumental in my creation of a debounce function in TypeScript, as showcased in my implementation, ensuring that the returned function aligns with the input function's signature.

In terms of specifying the function argument, I utilized generics in the following manner:

const debounce = function<T extends (...args: any) => any> (fn: T, delay: number) {

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using the return statement to set a value from a callback function in TypeScript

As I retrieve data from an array of class People, each person has an attendance list represented by Observable<any[]>. // Defining the Person class class Person { id: number; name: string; attendance: Observable<any[]>; // Represents ...

New approach in Typescript: Enhancement of child class with additional Event Listener overloads

One of my classes is structured like this: interface A extends EventEmitter{ on(event: "eventA", listener: () => void): this; } There is another class defined as follows: interface B extends A{ on(event: "eventB", listener: ...

The debate between using "this" versus "classname" to access static elements in

When working with TypeScript, I've observed that there are multiple valid approaches for accessing a static class member. class MyClass { private static readonly FOO: string = "foo"; public DoSomething(): void { console.log(MyClass.FOO);} pu ...

Tips for utilizing an object key containing a dash ("-") within it

Here is an example of the object structure: { approved_for_syndication: 1 caption: "" copyright: "" media-metadata: (3) [{…}, {…}, {…}] subtype: "photo" } How can I properly a ...

Creating a versatile class by extending a mixin in TypeScript

Being relatively new to TypeScript, I'm looking to initialize an object for response data as shown below: const auth = new ResponseData<Clazz>(); I have a mixin called BaseResponseHelper as follows: type Constructor<T = object> = new (... ...

Is it possible to use Date as a key in a Typescript Map?

Within my application, I have a requirement for mapping objects according to specific dates. Given that typescript provides both the Map and Date objects, I initially assumed this task would be straightforward. let map: Map<Date, MyObject> = new M ...

The 'src' properties in nextjs/image are of different types and therefore cannot be used interchangeably

I'm currently using React Dropzone to upload multiple images in my basic application. To display the types of images that are being dropped, I created a separate component with TypeScript. However, Next.js is throwing an error when it comes to the ima ...

Alter text within a string situated between two distinct characters

I have the following sentence with embedded links that I want to format: text = "Lorem ipsum dolor sit amet, [Link 1|www.example1.com] sadipscing elitr, sed diam nonumy [Link 2|www.example2.com] tempor invidunt ut labore et [Link 3|www.example3.com] m ...

Losing the generic type in nested interfaces

Having issues with generics and 'nested' interfaces when working with ReadonlyArray. Is there a way to utilize the filterList function without losing the type for the list parameter? interface INumber { value: number } interface IState { ...

Utilizing WebWorkers with @mediapipe/tasks-vision (Pose Landmarker): A Step-by-Step Guide

I've been experimenting with using a web worker to detect poses frame by frame, and then displaying the results on the main thread. However, I'm encountering some delays and synchronization issues. My setup involves Next.js 14.0.4 with @mediapip ...

In AngularJS, the use of the '+' operator is causing concatenation instead of addition

Looking for assistance with my TypeScript code where I've created a basic calculator. Everything is working as expected except for addition, which seems to be concatenating the numbers instead of adding them together. HTML CODE : <input type="tex ...

The issue with downloading all files in Firefox persists when attempting to download multiple files simultaneously due to an anchor click

I am currently facing an issue with downloading multiple files using TypeScript in Angular 6. I am receiving an array of blobs from a web API service. Here is the service method used to get multiple blobs for downloading: private downloadTest(): void { ...

Why am I receiving the error message "Argument of type 'number' is not assignable to parameter of type 'never'?"

import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { showSecret = false; logArr ...

The module cannot be located: Unable to find '../typings' in '/vercel/path0/pages'

Having trouble deploying my Next.js website through Vercel. It seems to be stuck at this stage. Can someone assist me, please? I've attempted deleting the node_modules folder and package-lock.json, then running npm install again, but unfortunately it ...

Guide on troubleshooting *.ts files in an ionic 2 project using Chrome's inspect devices feature

After successfully creating my Ionic 2 application for Android using the command "ionic build android", everything seems to be working fine. I have been debugging the app by using Chrome inspect devices, but now I am facing an issue. I am trying to debug ...

Challenges arising from the usage of Vue component state in TypeScript

I'm encountering an issue with a basic Vue component. I'm attempting to trigger a rerender of v-if="isTouched" by setting the setter (via the touch event). Vue dev tools indicate that the _isTouched variable is showing as "undefined". My underst ...

Webpack is encountering difficulties in locating the entry module when working with typescript

I've been working on integrating webpack into my typescript application. To get a better understanding of webpack, I decided to do a minimal migration. I started by cloning the Angular2 quickstart seed and added a webpack.config.js: 'use strict& ...

The comparison between importing TypeScript and ES2015 modules

I am currently facing an issue with TypeScript not recognizing the "default export" of react. Previously, in my JavaScript files, I used: import React from 'react'; import ReactDOM from 'react-dom'; However, in TypeScript, I found tha ...

Can TypeScript be set up to include undefined as a potential type in optional chains?

Today, I encountered a bug that I believe should have been caught by the type system. Let me illustrate with an example: function getModel(): Model { /* ... */ } function processModelName(name: string) { return name.replace('x', 'y& ...

Incorrect line numbers displayed in component stack trace [TypeScript + React]

Challenge I am currently working on integrating an error boundary into my client-side React application. During development, I aim to showcase the error along with a stack trace within the browser window, similar to the error overlays found in create-reac ...