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

          How to preserve electronics (computers, tablets and phones) for hundreds of years Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern) The network's official Twitter account is up and running again. What content…How might modern humans leave a message for 50,000 years?How would an aquatic race develop computers?How do we make computers care for human life?Keeping supplies for 1000 yearsWhat will cell phones become in 100 years?What body armor protects against a laser?Could a society attain 1800s technology if limited to using copper and bronze?Electricity power (magic) and electronicsScavenging metal resources in post-apocalypse after 100 yearsWhy would precursors create devices that can survive and still work after hundreds of years?

          155 수학 과학 기타 둘러보기 메뉴eh추가해eh문서를 완성해

          Convert JSON to MapSimplest way to convert a string representing JSON array into Java array List of key value pairsHow to take String JSON values into HashMapConvert a JSON String to a HashMapCreating BSON object from JSON stringJSONObject - How to get a value ?Better Map ConstructorReading JSON from Url javaUpdate columns if input values are not null otherwise ignore and keep the existing values of column in databaseHow to store object represented as Json string into Couchbase Lite?Go JSON into MapHow do I efficiently iterate over each entry in a Java Map?Sort a Map<Key, Value> by valuesHow to round a number to n decimal places in JavaCan comments be used in JSON?How do I read / convert an InputStream into a String in Java?How can I pretty-print JSON in a shell script?What is the correct JSON content type?How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?Why does Google prepend while(1); to their JSON responses?Parse JSON in JavaScript?