Is there a way to access the callback function's arguments and its return value from outside the function?

Is it possible to access both the callback function argument and the return value of a function that takes a callback function as an argument, outside of the function?

Consider the following example with a function called func_a.

function func_a(callback:(arg:string)=>void){
  callback("callback arg")
  return "func_a return"
}

I am curious if there is a way to extract both the callback function argument, "callback arg", and the function return value, "func_a return", from outside of func_a.

In the code snippet below, we use Promise and then to access the arguments provided to the callback function but not the return value of func_a.

new Promise<string>(
  (resolve)=>{
    const func_a_return = func_a((arg)=>resolve(arg))
  }
).then((arg)=>{console.log(arg)})

This question specifically pertains to retrieving values from callbacks such as onSnapshot in Firestore, where I want to access both the callback argument snapshot and the return value unsubscribe externally.

Answer №1

This is a query regarding the functionality of onSnapshot in Firestore. I was interested in retrieving both the callback function argument snapshot and the unsubscribe function return value from outside the onSnapshot function.

Unlike the example with func_a, the onSnapshot does not execute the callback synchronously. This means that initially, onSnapshot will return the unsubscribe function, and only after the execution clears the call stack will the callback be triggered.

As a result, you can access the unsubscribe function within the callback itself. For instance, you can use it like this:

const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
    unsub();
    // Perform actions with `doc` here or call another function with `doc` as an argument.
});

If your intention was to access the document immediately after the onSnapshot is called, unfortunately, you won't be able to do so. Since the callback hasn't executed yet, the document information won't be available at that point.

Answer №2

I'm not quite certain about what you're searching for, but here is some information that might assist you:

function func_a(callback:(arg:string)=>number){
  callback("callback arg")
  return "func_a returned"
}

type Callback = Parameters<typeof func_a>[0]; // (arg:string)=>number
type ReturnCb = ReturnType<Callback>; // number

typescript playground

Answer №3

Big shoutout to tricot's exceptional solution, which resolved all of my queries. I am now taking the opportunity to craft a comprehensive response to my question based on the provided answer.

To begin with, it is crucial to note that onSnapshot invokes the callback function asynchronously. To replicate this behavior within my own function func_a, adjustments must be made to my initial code snippet as illustrated below:

function func_a(callback:(arg:string)=>void){
  setTimeout(
    callback.bind(null,"callback argument"),
    1000
  )
  return "func_a result"
}

To capture both the callback argument and the function return value outside the function, the following code can achieve that purpose:

type CallbackArgumentAndFunctionResult={
  callback_argument:string,
  function_result:string
}

new Promise<CallbackArgumentAndFunctionResult>(
  (resolve)=>{
    const function_return=func_a(
      (arg)=>resolve({
        callback_argument:arg,
        function_result:function_return
      })
    )
  }
).then((arg_res)=>{
  console.log(arg_res.callback_argument)
  console.log(arg_res.function_result)
})

With the execution of the callback function being asynchronous post function value return, accessing the return value inside the callback enables simultaneous retrieval of both values, thereby serving as the foundation for compiling the aforementioned code.

This methodology empowers me to emulate the intended functionality of onSnapshot. For instance, in a React setting, I can segregate the unsubscribe function and snapshot from onSnapshot, demonstrated as follows:

export default function Home(){
  const [myUnsubscribe,setMyUnsubscribe]=useState<Unsubscribe|undefined>()
  const ObtainCity=()=>new Promise<SnapshotUnsubscribe>((resolve)=>{
    const unsubscribe = onSnapshot(
      doc(db, "cities", "SF"),
      (snapshot)=>resolve({ snapshot, unsubscribe })
    )
  })
  
  useEffect(
    ()=>{
      ObtainCity().then(({snapshot, unsubscribe})=>{
        setMyUnsubscribe(unsubscribe)
      })
      return ()=>{myUnsubscribe && myUnsubscribe()}
    },[]
  )

  return <div></div>
}

Furthermore, a resolution to my query regarding the initial code example where the callback function precedes the return value is elaborated upon:

As the function returns the value subsequent to executing the callback function, immediate resolution within the callback function would fail to assign the return value. Hence, the following code emphasizes introducing an asynchronous delay in the callback function prior to resolving:

function func_a(callback:(arg:string)=>void){
  callback("callback argument")
  return "func_a result"
}

type CallbackArgumentAndFunctionResult={
  callback_argument:string,
  function_result:string
}

new Promise<CallbackArgumentAndFunctionResult>(
  (resolve)=>{
    const function_return=func_a((arg)=>{
      setTimeout(
        ()=>{
          resolve({
            callback_argument:arg,
            function_result:function_return
          })
        },
        1000)
    })
  }
).then((arg_res)=>{
  console.log(arg_res.callback_argument)
  console.log(arg_res.function_result)
})

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

What is the best way to consistently and frequently invoke a REST API in Angular 8 using RxJS?

I have developed a REST API that retrieves a list of values. My goal is to immediately invoke this API to fetch values and store them in a component's member variable. Subsequently, I plan to refresh the data every five minutes. Upon conducting some ...

Confirm the presence of a particular sub collection within Firebase/Firestore by returning true

Can you confirm if the sub-collection named 'categories' exists within the users collection in Firestore? Please return true if it exists and false if it does not. ...

Error encountered in React TypeScript: Expected symbol '>' was not found during parsing

While transitioning from JavaScript to TypeScript, I encountered an error in my modified code: Error on Line 26:8: Parsing error: '>' expected import React from "react"; import { Route, Redirect, RouteProps } from "react-router ...

Enhancing class functionality with decorators in TypeScript

Over on the TypeScript's Decorator reference page, there is a code snippet showcasing how to override a constructor with a class decorator: function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) { return class extends con ...

After the completion of populating, you can access the Node.js hashmap in AWS Lambda

Currently working on a lambda function in AWS, navigating the world of node.js for the first time. I suspect that the issue I'm facing is related to nodejs being asynchronous and could potentially be resolved with promises / async / await. However, no ...

How can I upload multiple images in one request using Typescript?

HTML: <div> <input type ="file" (change)="selectFiles($event)" multiple="multiple" /> </div> Function to handle the change event selectFiles(event) { const reader = new FileReader(); if (event.target.files & ...

Tips for including and excluding personalized Chips from input

Just started learning React/typescript, any assistance would be greatly appreciated Custom Chip (CC.chip) is a specialized Chip UI component that can be utilized as demonstrated below. const [isOpen, setIsOpen] = useState(true); const onClose = Re ...

Exploring the power of Angular through the use of promises with multiple

I've come across some forum discussions about angular promises in the past, but I'm having trouble implementing them in my current situation. My backend is nodejs/locomotive and frontend is Angular. In the controller code below, I am trying to a ...

Tips for utilizing the randomColor library

Looking for guidance on incorporating the randomColor package from yarn to assign colors to various columns in a table within my project. Any examples or resources would be greatly appreciated! I am specifically working with React and Typescript. ...

What is the best way to define the type of an object in TypeScript when passing it to a function

I am currently working on a function that accepts an object of keys with values that have specific types. The type for one field is determined by the type of another field in the same object. Here is the code: // Consider this Alpha type and echo function. ...

Empty Firebase currentUser Redirected After Successful Sign In

I have a webpage named index.html which serves as the sign-in page. After a user successfully signs in, I want to redirect them to a new page called home.html, where their email will be displayed. However, I am encountering an issue with getting a null va ...

Creating a data structure that consists of pairs of elements, inspired by the alignment of domino bricks, using TypeScript syntax

My goal is to establish a type alias in TypeScript that allows all values which are arrays of Domino pairs, where each pair connects like domino bricks: Pair<A,B> connects with Pair<C,D> only if B = C. For example: const chain1: DominoChain = ...

Is it possible to duplicate a response before making changes to its contents?

Imagine we are developing a response interceptor for an Angular 4 application using the HttpClient: export class MyInterceptor implements HttpInterceptor { public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<an ...

Tips on utilizing the `arguments` property in scenarios where Parameters<...> or a similar approach is anticipated

How can you pass the arguments of a function into another function without needing to assert the parameters? Example: function f(a:number, b:number){ let args:Parameters<typeof f> = arguments // Error: Type 'IArguments' is not assignab ...

Altering the properties of a specified element within TestBed using the overrideComponent method

We are implementing TestBed.overrideComponent() to substitute a component with custom behavior. TestBed.overrideComponent(CoolComponent, { set: { template: '<div id="fake-component">i am the fake component</div>', sel ...

What is preventing the deletion of a local Firebase document, whereas the deployed version is successful in doing so?

Currently, I have successfully deployed a Firebase Node.js backend and it is running smoothly locally using firebase serve for initial development. I am able to add and update documents both locally (utilizing Postman to simulate an external REST API) and ...

Using the currency pipe with a dynamic variable in Angular 2

My application utilizes CurrencyPipe, The current implementation is functional, <div class="price">{{123 | currConvert | currency:'USD':true:'3.2-2'}}</div> Now, I need to dynamically pass the currency from a model varia ...

Tips for ensuring that the DOM is fully rendered before executing any code

Before proceeding to the next functions, it is necessary to wait for the DOM to finish rendering. The flow or lifecycle of this process is outlined below: Adding an item to the Array: this.someFormArray.push((this.createForm({ name: 'Name& ...

I encountered an issue while attempting to retrieve data using route parameters. It seems that I am unable to access the 'imagepath' property as it is undefined

Is there a way to access data when the page loads, even if it is initially undefined? I keep getting this error message: "ERROR TypeError: Cannot read properties of undefined (reading 'imagepath')". How can I resolve this issue? import { Compone ...

What causes the discrepancy in results between these two NodeJS/Typescript imports?

Within my NodeJS project, I have integrated typescript version 3.2 alongside express version 4.16 and @types/express version 4.16. My development is focused on using Typescript with the intention of transpiling it later on. The guidelines for @types/expre ...