How to type annotate “function wrappers” (function which returns a function with the same signature as it's argument)Higher order function, Flow type annotationsWhat is the correct way to define types for Redux actions?How do I flow-annotate a clone function?type-checking function signatures with less or more argumentsflow-type annotations for lodash find()flowtype error on react-redux 'connect'Allowing a promise.all-like function to return optionally null results with flowHow to properly type this `makeCancellable` function and make Flowtype stop complaining?Why imported type goes error while the exact same type in local file goes fine in Flow function intersection

Compare FEM mesh with the mesh created within Mathematica

In Bb5 systems against the Sicilian, why does White exchange their b5 bishop without playing a6?

What is the maximum viable speed for a projectile within earth's atmosphere?

Persuading players to be less attached to a pre-session 0 character concept

Cemented carbide swords - worth it?

How do you determine which representation of a function to use for Newton's method?

What's the purpose of autocorrelation?

What's the benefit of prohibiting the use of techniques/language constructs that have not been taught?

Other than good shoes and a stick, what are some ways to preserve your knees on long hikes?

Minimum number of lines to draw 111 squares

Simple way to decompose a lists in a certain way?

Account creation and log-in system

We suspect colleague is stealing company code - what do we do?

How to convey to the people around me that I want to disengage myself from constant giving?

When would open interest equal trading volume?

What is the word for a person who destroys monuments?

Amiga 500 OCS/ECS vs Mega Drive VDP

Manager manipulates my leaves, what's in it for him?

(How long) Should I indulge my new co-workers?

EU compensation - fire alarm at the Flight Crew's hotel

Unpredictability of Stock Market

Is it safe to unplug a blinking USB drive after 'safely' ejecting it?

Secondary characters in character-study fiction

Why do things cool off?



How to type annotate “function wrappers” (function which returns a function with the same signature as it's argument)


Higher order function, Flow type annotationsWhat is the correct way to define types for Redux actions?How do I flow-annotate a clone function?type-checking function signatures with less or more argumentsflow-type annotations for lodash find()flowtype error on react-redux 'connect'Allowing a promise.all-like function to return optionally null results with flowHow to properly type this `makeCancellable` function and make Flowtype stop complaining?Why imported type goes error while the exact same type in local file goes fine in Flow function intersection






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








2















Is there a way to properly tell flow that I'm returning a function with the same signature as the function I'm passed, but not exactly the same function ?



This is an example of a "once" wrapper which prevents a function from being called multiple times, it works but uses an any-cast internally to make flow give up, I'd like to get rid of that cast and have 100% coverage:



module.exports.once = /*::<F:Function>*/(f /*:F*/) /*:F*/ => 
let guard = false;
return ((function ()
if (guard) return;
guard = true;
return f.apply(null, arguments);
/*:any*/) /*:F*/);
;









share|improve this question






























    2















    Is there a way to properly tell flow that I'm returning a function with the same signature as the function I'm passed, but not exactly the same function ?



    This is an example of a "once" wrapper which prevents a function from being called multiple times, it works but uses an any-cast internally to make flow give up, I'd like to get rid of that cast and have 100% coverage:



    module.exports.once = /*::<F:Function>*/(f /*:F*/) /*:F*/ => 
    let guard = false;
    return ((function ()
    if (guard) return;
    guard = true;
    return f.apply(null, arguments);
    /*:any*/) /*:F*/);
    ;









    share|improve this question


























      2












      2








      2


      1






      Is there a way to properly tell flow that I'm returning a function with the same signature as the function I'm passed, but not exactly the same function ?



      This is an example of a "once" wrapper which prevents a function from being called multiple times, it works but uses an any-cast internally to make flow give up, I'd like to get rid of that cast and have 100% coverage:



      module.exports.once = /*::<F:Function>*/(f /*:F*/) /*:F*/ => 
      let guard = false;
      return ((function ()
      if (guard) return;
      guard = true;
      return f.apply(null, arguments);
      /*:any*/) /*:F*/);
      ;









      share|improve this question














      Is there a way to properly tell flow that I'm returning a function with the same signature as the function I'm passed, but not exactly the same function ?



      This is an example of a "once" wrapper which prevents a function from being called multiple times, it works but uses an any-cast internally to make flow give up, I'd like to get rid of that cast and have 100% coverage:



      module.exports.once = /*::<F:Function>*/(f /*:F*/) /*:F*/ => 
      let guard = false;
      return ((function ()
      if (guard) return;
      guard = true;
      return f.apply(null, arguments);
      /*:any*/) /*:F*/);
      ;






      flowtype






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 28 at 13:44









      Caleb James DeLisleCaleb James DeLisle

      132 bronze badges




      132 bronze badges

























          1 Answer
          1






          active

          oldest

          votes


















          1
















          Okay, first things first.



          Your return value can currently never match F without your casting through any because the signature of the function you're returning is not the same because it can return undefined where the original may not.



          (comment syntax removed for readability)



          module.exports.once = <F: Function>(f: F): F => 
          let guard = false;
          return ((function () // this function returns the return value of F or void
          if (guard) return; // returning void
          guard = true;
          return f.apply(null, arguments);
          : any): F);
          ;


          But to start typing this, we're gonna need to break down that function generic a little bit.



          First of all, let's not use Function as it's generally better if we don't:




          However, if you need to opt-out of the type checker, and don’t want to go all the way to any, you can instead use Function. Function is unsafe and should be avoided.




          Also, we're going to extract the types of the arguments and the return value so we can manipulate them independently and construct a return type. We'll call them Args and Return so they're easy to follow.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ) ((...Array<Args>) => Return | void) => void`
          let guard = false;
          return function ()
          if (guard) return;
          guard = true;
          return f.apply(null, arguments);
          ;
          ;


          Now that we're taking into account that our new function might return void everything type checks fine. But of course, the return type of our once function will no longer match the type of the passed function.



          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once(func); // error!
          // Cannot assign `module.exports.once(...)` to `onceFunc` because
          // undefined [1] is incompatible with string [2] in the return value.


          Makes sense, right?



          So, let's discuss the signature of this function. We want our return value to have the same signature as the function we pass in. Currently it doesn't because we're adding void to the signature. Do we need to? Why are we returning undefined? How can we always return the same type from our onced function? Well, one option would be to store the return value from the single call to the function and always return the stored return value for subsequent calls. This would kind of make sense because the whole point is to allow multiple calls but not perform any of the functions effects. So this way we can avoid changing the interface of the function, so we really don't need to know whether or not the function has been called before.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ): ((...Array<Args>) => Return) =>
          let guard = false;
          let returnValue: Return;
          return function ()
          if (guard) return returnValue;
          guard = true;
          returnValue = f.apply(null, arguments);
          return returnValue;
          ;
          ;


          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once2(func);


          One good question to ask at this point would be, why do the types match even if we're not technically returning exactly F? The answer to that is because functions in flow are structurally typed. So if they have the same arguments and return value, their types match.






          share|improve this answer

























          • function wrapped by once should have the same type of arguments. We can change F: (...Array<Args>) => Return to F: (...Array<*>) => Return and let flow to infer types

            – Buggy
            Apr 6 at 13:26











          • * is actually deprecated.

            – Lyle Underwood
            Apr 30 at 18:21










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );














          draft saved

          draft discarded
















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55399158%2fhow-to-type-annotate-function-wrappers-function-which-returns-a-function-with%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1
















          Okay, first things first.



          Your return value can currently never match F without your casting through any because the signature of the function you're returning is not the same because it can return undefined where the original may not.



          (comment syntax removed for readability)



          module.exports.once = <F: Function>(f: F): F => 
          let guard = false;
          return ((function () // this function returns the return value of F or void
          if (guard) return; // returning void
          guard = true;
          return f.apply(null, arguments);
          : any): F);
          ;


          But to start typing this, we're gonna need to break down that function generic a little bit.



          First of all, let's not use Function as it's generally better if we don't:




          However, if you need to opt-out of the type checker, and don’t want to go all the way to any, you can instead use Function. Function is unsafe and should be avoided.




          Also, we're going to extract the types of the arguments and the return value so we can manipulate them independently and construct a return type. We'll call them Args and Return so they're easy to follow.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ) ((...Array<Args>) => Return | void) => void`
          let guard = false;
          return function ()
          if (guard) return;
          guard = true;
          return f.apply(null, arguments);
          ;
          ;


          Now that we're taking into account that our new function might return void everything type checks fine. But of course, the return type of our once function will no longer match the type of the passed function.



          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once(func); // error!
          // Cannot assign `module.exports.once(...)` to `onceFunc` because
          // undefined [1] is incompatible with string [2] in the return value.


          Makes sense, right?



          So, let's discuss the signature of this function. We want our return value to have the same signature as the function we pass in. Currently it doesn't because we're adding void to the signature. Do we need to? Why are we returning undefined? How can we always return the same type from our onced function? Well, one option would be to store the return value from the single call to the function and always return the stored return value for subsequent calls. This would kind of make sense because the whole point is to allow multiple calls but not perform any of the functions effects. So this way we can avoid changing the interface of the function, so we really don't need to know whether or not the function has been called before.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ): ((...Array<Args>) => Return) =>
          let guard = false;
          let returnValue: Return;
          return function ()
          if (guard) return returnValue;
          guard = true;
          returnValue = f.apply(null, arguments);
          return returnValue;
          ;
          ;


          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once2(func);


          One good question to ask at this point would be, why do the types match even if we're not technically returning exactly F? The answer to that is because functions in flow are structurally typed. So if they have the same arguments and return value, their types match.






          share|improve this answer

























          • function wrapped by once should have the same type of arguments. We can change F: (...Array<Args>) => Return to F: (...Array<*>) => Return and let flow to infer types

            – Buggy
            Apr 6 at 13:26











          • * is actually deprecated.

            – Lyle Underwood
            Apr 30 at 18:21















          1
















          Okay, first things first.



          Your return value can currently never match F without your casting through any because the signature of the function you're returning is not the same because it can return undefined where the original may not.



          (comment syntax removed for readability)



          module.exports.once = <F: Function>(f: F): F => 
          let guard = false;
          return ((function () // this function returns the return value of F or void
          if (guard) return; // returning void
          guard = true;
          return f.apply(null, arguments);
          : any): F);
          ;


          But to start typing this, we're gonna need to break down that function generic a little bit.



          First of all, let's not use Function as it's generally better if we don't:




          However, if you need to opt-out of the type checker, and don’t want to go all the way to any, you can instead use Function. Function is unsafe and should be avoided.




          Also, we're going to extract the types of the arguments and the return value so we can manipulate them independently and construct a return type. We'll call them Args and Return so they're easy to follow.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ) ((...Array<Args>) => Return | void) => void`
          let guard = false;
          return function ()
          if (guard) return;
          guard = true;
          return f.apply(null, arguments);
          ;
          ;


          Now that we're taking into account that our new function might return void everything type checks fine. But of course, the return type of our once function will no longer match the type of the passed function.



          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once(func); // error!
          // Cannot assign `module.exports.once(...)` to `onceFunc` because
          // undefined [1] is incompatible with string [2] in the return value.


          Makes sense, right?



          So, let's discuss the signature of this function. We want our return value to have the same signature as the function we pass in. Currently it doesn't because we're adding void to the signature. Do we need to? Why are we returning undefined? How can we always return the same type from our onced function? Well, one option would be to store the return value from the single call to the function and always return the stored return value for subsequent calls. This would kind of make sense because the whole point is to allow multiple calls but not perform any of the functions effects. So this way we can avoid changing the interface of the function, so we really don't need to know whether or not the function has been called before.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ): ((...Array<Args>) => Return) =>
          let guard = false;
          let returnValue: Return;
          return function ()
          if (guard) return returnValue;
          guard = true;
          returnValue = f.apply(null, arguments);
          return returnValue;
          ;
          ;


          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once2(func);


          One good question to ask at this point would be, why do the types match even if we're not technically returning exactly F? The answer to that is because functions in flow are structurally typed. So if they have the same arguments and return value, their types match.






          share|improve this answer

























          • function wrapped by once should have the same type of arguments. We can change F: (...Array<Args>) => Return to F: (...Array<*>) => Return and let flow to infer types

            – Buggy
            Apr 6 at 13:26











          • * is actually deprecated.

            – Lyle Underwood
            Apr 30 at 18:21













          1














          1










          1









          Okay, first things first.



          Your return value can currently never match F without your casting through any because the signature of the function you're returning is not the same because it can return undefined where the original may not.



          (comment syntax removed for readability)



          module.exports.once = <F: Function>(f: F): F => 
          let guard = false;
          return ((function () // this function returns the return value of F or void
          if (guard) return; // returning void
          guard = true;
          return f.apply(null, arguments);
          : any): F);
          ;


          But to start typing this, we're gonna need to break down that function generic a little bit.



          First of all, let's not use Function as it's generally better if we don't:




          However, if you need to opt-out of the type checker, and don’t want to go all the way to any, you can instead use Function. Function is unsafe and should be avoided.




          Also, we're going to extract the types of the arguments and the return value so we can manipulate them independently and construct a return type. We'll call them Args and Return so they're easy to follow.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ) ((...Array<Args>) => Return | void) => void`
          let guard = false;
          return function ()
          if (guard) return;
          guard = true;
          return f.apply(null, arguments);
          ;
          ;


          Now that we're taking into account that our new function might return void everything type checks fine. But of course, the return type of our once function will no longer match the type of the passed function.



          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once(func); // error!
          // Cannot assign `module.exports.once(...)` to `onceFunc` because
          // undefined [1] is incompatible with string [2] in the return value.


          Makes sense, right?



          So, let's discuss the signature of this function. We want our return value to have the same signature as the function we pass in. Currently it doesn't because we're adding void to the signature. Do we need to? Why are we returning undefined? How can we always return the same type from our onced function? Well, one option would be to store the return value from the single call to the function and always return the stored return value for subsequent calls. This would kind of make sense because the whole point is to allow multiple calls but not perform any of the functions effects. So this way we can avoid changing the interface of the function, so we really don't need to know whether or not the function has been called before.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ): ((...Array<Args>) => Return) =>
          let guard = false;
          let returnValue: Return;
          return function ()
          if (guard) return returnValue;
          guard = true;
          returnValue = f.apply(null, arguments);
          return returnValue;
          ;
          ;


          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once2(func);


          One good question to ask at this point would be, why do the types match even if we're not technically returning exactly F? The answer to that is because functions in flow are structurally typed. So if they have the same arguments and return value, their types match.






          share|improve this answer













          Okay, first things first.



          Your return value can currently never match F without your casting through any because the signature of the function you're returning is not the same because it can return undefined where the original may not.



          (comment syntax removed for readability)



          module.exports.once = <F: Function>(f: F): F => 
          let guard = false;
          return ((function () // this function returns the return value of F or void
          if (guard) return; // returning void
          guard = true;
          return f.apply(null, arguments);
          : any): F);
          ;


          But to start typing this, we're gonna need to break down that function generic a little bit.



          First of all, let's not use Function as it's generally better if we don't:




          However, if you need to opt-out of the type checker, and don’t want to go all the way to any, you can instead use Function. Function is unsafe and should be avoided.




          Also, we're going to extract the types of the arguments and the return value so we can manipulate them independently and construct a return type. We'll call them Args and Return so they're easy to follow.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ) ((...Array<Args>) => Return | void) => void`
          let guard = false;
          return function ()
          if (guard) return;
          guard = true;
          return f.apply(null, arguments);
          ;
          ;


          Now that we're taking into account that our new function might return void everything type checks fine. But of course, the return type of our once function will no longer match the type of the passed function.



          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once(func); // error!
          // Cannot assign `module.exports.once(...)` to `onceFunc` because
          // undefined [1] is incompatible with string [2] in the return value.


          Makes sense, right?



          So, let's discuss the signature of this function. We want our return value to have the same signature as the function we pass in. Currently it doesn't because we're adding void to the signature. Do we need to? Why are we returning undefined? How can we always return the same type from our onced function? Well, one option would be to store the return value from the single call to the function and always return the stored return value for subsequent calls. This would kind of make sense because the whole point is to allow multiple calls but not perform any of the functions effects. So this way we can avoid changing the interface of the function, so we really don't need to know whether or not the function has been called before.



          module.exports.once = <Args, Return, F: (...Array<Args>) => Return>(
          f: F
          ): ((...Array<Args>) => Return) =>
          let guard = false;
          let returnValue: Return;
          return function ()
          if (guard) return returnValue;
          guard = true;
          returnValue = f.apply(null, arguments);
          return returnValue;
          ;
          ;


          type Func = (number) => string;

          const func: Func = (n) => n.toString();

          const onceFunc: Func = module.exports.once2(func);


          One good question to ask at this point would be, why do the types match even if we're not technically returning exactly F? The answer to that is because functions in flow are structurally typed. So if they have the same arguments and return value, their types match.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 30 at 17:55









          Lyle UnderwoodLyle Underwood

          5671 silver badge8 bronze badges




          5671 silver badge8 bronze badges















          • function wrapped by once should have the same type of arguments. We can change F: (...Array<Args>) => Return to F: (...Array<*>) => Return and let flow to infer types

            – Buggy
            Apr 6 at 13:26











          • * is actually deprecated.

            – Lyle Underwood
            Apr 30 at 18:21

















          • function wrapped by once should have the same type of arguments. We can change F: (...Array<Args>) => Return to F: (...Array<*>) => Return and let flow to infer types

            – Buggy
            Apr 6 at 13:26











          • * is actually deprecated.

            – Lyle Underwood
            Apr 30 at 18:21
















          function wrapped by once should have the same type of arguments. We can change F: (...Array<Args>) => Return to F: (...Array<*>) => Return and let flow to infer types

          – Buggy
          Apr 6 at 13:26





          function wrapped by once should have the same type of arguments. We can change F: (...Array<Args>) => Return to F: (...Array<*>) => Return and let flow to infer types

          – Buggy
          Apr 6 at 13:26













          * is actually deprecated.

          – Lyle Underwood
          Apr 30 at 18:21





          * is actually deprecated.

          – Lyle Underwood
          Apr 30 at 18:21








          Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.







          Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.




















          draft saved

          draft discarded















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55399158%2fhow-to-type-annotate-function-wrappers-function-which-returns-a-function-with%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

          Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

          Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript