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

TypeORM find query is returning a data type that does not match the defined entity type

In my infrastructure module, I am using the code snippet below: import { Student } from "core" import { Repository } from "./Repository" import { Database } from "../../db" export class UserRepository<Student> extends Re ...

Neglecting the error message for type assignment in the Typescript compiler

Presented here is a scenario I am facing: const customer = new Customer(); let customerViewModel = new CustomerLayoutViewModel(); customerViewModel = customer; Despite both Customer and CustomerLayoutViewModel being identical at the moment, there is no ...

The type of the element is implicitly set to 'any' because the expression 'keyof IMyObj' cannot be used to index the type

Trying to avoid specifying types in TypeScript and setting a value by accessing its key is causing a TypeScript error. Despite looking at multiple StackOverflow posts, I couldn't find a solution. I encountered a similar issue with my code and tried r ...

The initial character of the input must always be a letter

I need assistance with an input element that requires 5 characters, with the first character being a letter: <input mdInput #acronyme placeholder="Company" type="text" maxlength="5" minlength="5" required [value]="acronyme.value.toUpperCase()"> Th ...

Issue with undefined arrays in the Angular merge sort visualization tool

I am currently working on developing a visualizer for sorting algorithms using Angular. However, I have encountered some difficulties while implementing merge sort. As a Java programmer, I suspect that there may be an issue with my TypeScript code and the ...

Encountering challenges while transitioning from ngrx version 2 to version 4, specifically related to typing in array de-structuring

The error indicates a missing comma after the action parameter in the .map. Another error pops up when hovering over DataActions.AddDataAction, displaying Tuple type '[Action, AppStore]' with length '2' cannot be assigned to tuple with ...

Having trouble rendering Next.JS dynamic pages using router.push()? Find out how to fix routing issues in your

The issue I am facing revolves around the visibility of the navbar component when using route.push(). It appears that the navbar is not showing up on the page, while the rest of the content including the footer is displayed. My goal is to navigate to a dy ...

The value I'm receiving for my list of objects is not accurate

Currently, I'm experimenting with implementing TYPEHEAD for user input using the ng-bootstrap library. The goal is to display a list of objects (similar to a select option without a dropdown box): HTML <input type="search" #instance="ngbTy ...

Acquiring a collection of objects retrieved from a set of URLs using rxjs and typescript

I have an item to work with: let DataObject = { 'item1' : './someitem1.json', 'item2' : './someitem2.json',.. }; I want to fetch all items using RxJS and notify the subscriber only after all items have been fe ...

What causes React Hook Form to return undefined upon submission?

I am currently working on a project using TypeScript. In this project, I have a form that should output 4 values after submitting the form. However, only the input field linked to the controller is sending a value, while the others are returning undefined: ...

Why does the Asnyc Express Middleware function as it does?

Hello! I am a newcomer to the world of Express/Node and could use some guidance and explanation. Suppose I have an async function serving as middleware, which inherently returns a promise immediately. Let's create a mock function for example: async ...

Transcompiling TypeScript for Node.js

I'm in the process of developing a Node project using Typescript, and I've configured the target option to es6 in my tsconfig.json file. Although Node version 8 does support the async/await syntax, Typescript automatically converts it to a gener ...

Using the spread operator to modify an array containing objects

I am facing a challenge with updating specific properties of an object within an array. I have an array of objects and I need to update only certain properties of a single object in that array. Here is the code snippet I tried: setRequiredFields(prevRequir ...

Definitions for Typescript types that describe a custom hook responsible for fetching a specific part of the Redux state

I've created a custom hook called useReduxState to fetch a specific piece of state from Redux like so: const STATE_A = useReduxState("STATE_A"); Now, I'm running into issues when trying to integrate Typescript. These are the types I a ...

Retrieve: Type 'string | undefined' does not match the parameter type 'RequestInfo'

When using the fetch function, I encountered an error with the "fetchUrl" argument: Error: Argument of type 'string | undefined' is not assignable to parameter of type 'RequestInfo'. This is the code snippet where the error occurred: ...

Strategies for displaying error messages in case of zero search results

I am currently developing a note-taking application and facing an issue with displaying error messages. The error message is being shown even when there are no search results, which is not the intended behavior. Can someone help me identify what I am doing ...

One efficient way to handle multiple concurrent tasks in NodeJs is by using the forEach method to iterate

Having trouble getting the promises to return any values, as they are coming back empty. Despite following suggestions on Stack Overflow, I am still unable to resolve this issue. Frustration levels are high and I'm feeling lost; Can anyone help me pi ...

Is your pure function component not receiving or responding to input props correctly?

Here is my code snippet: const actionCreators = { action: AppReducer.actionCreators.action } interface GlobalState { user: Model.User | null; } interface InputState { setStashBarWidth(width: number); stashWidth: number; } const Header = ...

Blend the power of Node's CommonJS with the versatility of Typescript's ES modules

I currently have a Node.js v10 legacy application that was built using CommonJS modules (require). The entire codebase is written in JavaScript. However, I am considering upgrading the app and refactoring a specific part of it to use TypeScript modules ( ...

Utilize key-value pairs to reference variables when importing as a namespace

Is it feasible to utilize a string for performing a lookup on an imported namespace, or am I approaching this the wrong way? Consider a file named my_file.ts with contents similar to: export const MyThing: CustomType = { propertyOne: "name", ...