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;
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
add a comment
|
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
add a comment
|
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
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
flowtype
asked Mar 28 at 13:44
Caleb James DeLisleCaleb James DeLisle
132 bronze badges
132 bronze badges
add a comment
|
add a comment
|
1 Answer
1
active
oldest
votes
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.
function wrapped byonce
should have the same type of arguments. We can changeF: (...Array<Args>) => Return
toF: (...Array<*>) => Return
and let flow to infer types
– Buggy
Apr 6 at 13:26
*
is actually deprecated.
– Lyle Underwood
Apr 30 at 18:21
add a comment
|
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
function wrapped byonce
should have the same type of arguments. We can changeF: (...Array<Args>) => Return
toF: (...Array<*>) => Return
and let flow to infer types
– Buggy
Apr 6 at 13:26
*
is actually deprecated.
– Lyle Underwood
Apr 30 at 18:21
add a comment
|
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.
function wrapped byonce
should have the same type of arguments. We can changeF: (...Array<Args>) => Return
toF: (...Array<*>) => Return
and let flow to infer types
– Buggy
Apr 6 at 13:26
*
is actually deprecated.
– Lyle Underwood
Apr 30 at 18:21
add a comment
|
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.
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.
answered Mar 30 at 17:55
Lyle UnderwoodLyle Underwood
5671 silver badge8 bronze badges
5671 silver badge8 bronze badges
function wrapped byonce
should have the same type of arguments. We can changeF: (...Array<Args>) => Return
toF: (...Array<*>) => Return
and let flow to infer types
– Buggy
Apr 6 at 13:26
*
is actually deprecated.
– Lyle Underwood
Apr 30 at 18:21
add a comment
|
function wrapped byonce
should have the same type of arguments. We can changeF: (...Array<Args>) => Return
toF: (...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
add a comment
|
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.
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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