TypeScript: void return type converted to any type?
I seem to be not able to comprehend why the following code does not raise error:
var rg: {(): void;} = ;
rg.push(function():string {return "";})
I clearly state that the type should be an array of functions that return void
, however I push there a function that returns a string
and yet the compiler does not complain. If I change the definition of rg
to
var rg: {():number;} = ;
The compiler starts to complain.
Is this a bug or is it how the void return type is supposed to work (i.e. anything goes if void
is used, basically making it the same as return type any
)?
typescript
add a comment |
I seem to be not able to comprehend why the following code does not raise error:
var rg: {(): void;} = ;
rg.push(function():string {return "";})
I clearly state that the type should be an array of functions that return void
, however I push there a function that returns a string
and yet the compiler does not complain. If I change the definition of rg
to
var rg: {():number;} = ;
The compiler starts to complain.
Is this a bug or is it how the void return type is supposed to work (i.e. anything goes if void
is used, basically making it the same as return type any
)?
typescript
add a comment |
I seem to be not able to comprehend why the following code does not raise error:
var rg: {(): void;} = ;
rg.push(function():string {return "";})
I clearly state that the type should be an array of functions that return void
, however I push there a function that returns a string
and yet the compiler does not complain. If I change the definition of rg
to
var rg: {():number;} = ;
The compiler starts to complain.
Is this a bug or is it how the void return type is supposed to work (i.e. anything goes if void
is used, basically making it the same as return type any
)?
typescript
I seem to be not able to comprehend why the following code does not raise error:
var rg: {(): void;} = ;
rg.push(function():string {return "";})
I clearly state that the type should be an array of functions that return void
, however I push there a function that returns a string
and yet the compiler does not complain. If I change the definition of rg
to
var rg: {():number;} = ;
The compiler starts to complain.
Is this a bug or is it how the void return type is supposed to work (i.e. anything goes if void
is used, basically making it the same as return type any
)?
typescript
typescript
edited Jul 13 '13 at 19:30
Drew Noakes
186k117527616
186k117527616
asked Oct 6 '12 at 16:34
Peter StJPeter StJ
6972820
6972820
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
This is by design (I'll explain why it's good design shortly). The spec says (in section 3.6.3, abridged for clarity):
A type S is assignable to a type T, and T is assignable from S, if one of the following is true...
S and T are object types and, for each member M in T, one of the following is true:
M is a call, construct or index signature and S contains a call, construct or index signature N where
- the result type of M is Void, or the result type of N is assignable to that of M.
In this case, we're testing if () => string
is assignable to () => void
. So either string
has to be assignable to void
(it isn't), or void
has to be void
(it is).
In effect, the rule here is you are allowed to throw away the return value, which is consistent with how e.g. C++ treats void
in template resolution.
function decrementWidgetHeight(w: Widget): number {
// ... returns the new height of the widget
}
function applyToManyWidgets(w: Widget, change: (x: Widget) => void): void {
// for each widget in the array, apply 'change' to it
}
// Later...
applyToManyWidgets(widgetsToShorten, decrementWidgetHeight); // Should be allowed?
When we constrain the type of change
to be (widget) => void
, we're making it so that you can pass decrementWidgetHeight
as the second argument even though it has a return value, but still making sure that when we write the body of applyToManyWidgets
, we don't accidentally use the return value of change
anywhere.
Note that void
is still different than any
because this is unallowed:
function f() { }
var x = f(); // Disallowed, f() is of type 'void'
+1 - you can test this using:var rg: {(): void;} = ; rg.push(function():string {return "";}) var x = rg[0]();
in the TypeScript playground to see the behaviour in action. Changevoid
tostring
and it will allow the return value to be used.
– Fenton
Oct 6 '12 at 22:14
Okay it makes sense, but is a little counter intuitive, i.e. allowing to add a function that does not match the type, even if it is void in the definition.
– Peter StJ
Oct 7 '12 at 17:55
2
The spec also says "void is only related to the types Undefined, Null and Any", so I'm not sure the spec is consistent. Definitely unexpected.
– Roly
Sep 26 '13 at 20:37
as of version 1.4.1.0 as I can see it is allowed to assign void functions calls
– shabunc
Jan 25 '15 at 22:23
add a comment |
That looks like a bug. You should open a new work item for the issue
Did that, but given the above comment I guess this is intended. Not finding generics much use in TS so far...
– Roly
Sep 26 '13 at 20:39
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/3.0/"u003ecc by-sa 3.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%2f12761607%2ftypescript-void-return-type-converted-to-any-type%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
This is by design (I'll explain why it's good design shortly). The spec says (in section 3.6.3, abridged for clarity):
A type S is assignable to a type T, and T is assignable from S, if one of the following is true...
S and T are object types and, for each member M in T, one of the following is true:
M is a call, construct or index signature and S contains a call, construct or index signature N where
- the result type of M is Void, or the result type of N is assignable to that of M.
In this case, we're testing if () => string
is assignable to () => void
. So either string
has to be assignable to void
(it isn't), or void
has to be void
(it is).
In effect, the rule here is you are allowed to throw away the return value, which is consistent with how e.g. C++ treats void
in template resolution.
function decrementWidgetHeight(w: Widget): number {
// ... returns the new height of the widget
}
function applyToManyWidgets(w: Widget, change: (x: Widget) => void): void {
// for each widget in the array, apply 'change' to it
}
// Later...
applyToManyWidgets(widgetsToShorten, decrementWidgetHeight); // Should be allowed?
When we constrain the type of change
to be (widget) => void
, we're making it so that you can pass decrementWidgetHeight
as the second argument even though it has a return value, but still making sure that when we write the body of applyToManyWidgets
, we don't accidentally use the return value of change
anywhere.
Note that void
is still different than any
because this is unallowed:
function f() { }
var x = f(); // Disallowed, f() is of type 'void'
+1 - you can test this using:var rg: {(): void;} = ; rg.push(function():string {return "";}) var x = rg[0]();
in the TypeScript playground to see the behaviour in action. Changevoid
tostring
and it will allow the return value to be used.
– Fenton
Oct 6 '12 at 22:14
Okay it makes sense, but is a little counter intuitive, i.e. allowing to add a function that does not match the type, even if it is void in the definition.
– Peter StJ
Oct 7 '12 at 17:55
2
The spec also says "void is only related to the types Undefined, Null and Any", so I'm not sure the spec is consistent. Definitely unexpected.
– Roly
Sep 26 '13 at 20:37
as of version 1.4.1.0 as I can see it is allowed to assign void functions calls
– shabunc
Jan 25 '15 at 22:23
add a comment |
This is by design (I'll explain why it's good design shortly). The spec says (in section 3.6.3, abridged for clarity):
A type S is assignable to a type T, and T is assignable from S, if one of the following is true...
S and T are object types and, for each member M in T, one of the following is true:
M is a call, construct or index signature and S contains a call, construct or index signature N where
- the result type of M is Void, or the result type of N is assignable to that of M.
In this case, we're testing if () => string
is assignable to () => void
. So either string
has to be assignable to void
(it isn't), or void
has to be void
(it is).
In effect, the rule here is you are allowed to throw away the return value, which is consistent with how e.g. C++ treats void
in template resolution.
function decrementWidgetHeight(w: Widget): number {
// ... returns the new height of the widget
}
function applyToManyWidgets(w: Widget, change: (x: Widget) => void): void {
// for each widget in the array, apply 'change' to it
}
// Later...
applyToManyWidgets(widgetsToShorten, decrementWidgetHeight); // Should be allowed?
When we constrain the type of change
to be (widget) => void
, we're making it so that you can pass decrementWidgetHeight
as the second argument even though it has a return value, but still making sure that when we write the body of applyToManyWidgets
, we don't accidentally use the return value of change
anywhere.
Note that void
is still different than any
because this is unallowed:
function f() { }
var x = f(); // Disallowed, f() is of type 'void'
+1 - you can test this using:var rg: {(): void;} = ; rg.push(function():string {return "";}) var x = rg[0]();
in the TypeScript playground to see the behaviour in action. Changevoid
tostring
and it will allow the return value to be used.
– Fenton
Oct 6 '12 at 22:14
Okay it makes sense, but is a little counter intuitive, i.e. allowing to add a function that does not match the type, even if it is void in the definition.
– Peter StJ
Oct 7 '12 at 17:55
2
The spec also says "void is only related to the types Undefined, Null and Any", so I'm not sure the spec is consistent. Definitely unexpected.
– Roly
Sep 26 '13 at 20:37
as of version 1.4.1.0 as I can see it is allowed to assign void functions calls
– shabunc
Jan 25 '15 at 22:23
add a comment |
This is by design (I'll explain why it's good design shortly). The spec says (in section 3.6.3, abridged for clarity):
A type S is assignable to a type T, and T is assignable from S, if one of the following is true...
S and T are object types and, for each member M in T, one of the following is true:
M is a call, construct or index signature and S contains a call, construct or index signature N where
- the result type of M is Void, or the result type of N is assignable to that of M.
In this case, we're testing if () => string
is assignable to () => void
. So either string
has to be assignable to void
(it isn't), or void
has to be void
(it is).
In effect, the rule here is you are allowed to throw away the return value, which is consistent with how e.g. C++ treats void
in template resolution.
function decrementWidgetHeight(w: Widget): number {
// ... returns the new height of the widget
}
function applyToManyWidgets(w: Widget, change: (x: Widget) => void): void {
// for each widget in the array, apply 'change' to it
}
// Later...
applyToManyWidgets(widgetsToShorten, decrementWidgetHeight); // Should be allowed?
When we constrain the type of change
to be (widget) => void
, we're making it so that you can pass decrementWidgetHeight
as the second argument even though it has a return value, but still making sure that when we write the body of applyToManyWidgets
, we don't accidentally use the return value of change
anywhere.
Note that void
is still different than any
because this is unallowed:
function f() { }
var x = f(); // Disallowed, f() is of type 'void'
This is by design (I'll explain why it's good design shortly). The spec says (in section 3.6.3, abridged for clarity):
A type S is assignable to a type T, and T is assignable from S, if one of the following is true...
S and T are object types and, for each member M in T, one of the following is true:
M is a call, construct or index signature and S contains a call, construct or index signature N where
- the result type of M is Void, or the result type of N is assignable to that of M.
In this case, we're testing if () => string
is assignable to () => void
. So either string
has to be assignable to void
(it isn't), or void
has to be void
(it is).
In effect, the rule here is you are allowed to throw away the return value, which is consistent with how e.g. C++ treats void
in template resolution.
function decrementWidgetHeight(w: Widget): number {
// ... returns the new height of the widget
}
function applyToManyWidgets(w: Widget, change: (x: Widget) => void): void {
// for each widget in the array, apply 'change' to it
}
// Later...
applyToManyWidgets(widgetsToShorten, decrementWidgetHeight); // Should be allowed?
When we constrain the type of change
to be (widget) => void
, we're making it so that you can pass decrementWidgetHeight
as the second argument even though it has a return value, but still making sure that when we write the body of applyToManyWidgets
, we don't accidentally use the return value of change
anywhere.
Note that void
is still different than any
because this is unallowed:
function f() { }
var x = f(); // Disallowed, f() is of type 'void'
answered Oct 6 '12 at 21:06
Ryan CavanaughRyan Cavanaugh
97.8k27168177
97.8k27168177
+1 - you can test this using:var rg: {(): void;} = ; rg.push(function():string {return "";}) var x = rg[0]();
in the TypeScript playground to see the behaviour in action. Changevoid
tostring
and it will allow the return value to be used.
– Fenton
Oct 6 '12 at 22:14
Okay it makes sense, but is a little counter intuitive, i.e. allowing to add a function that does not match the type, even if it is void in the definition.
– Peter StJ
Oct 7 '12 at 17:55
2
The spec also says "void is only related to the types Undefined, Null and Any", so I'm not sure the spec is consistent. Definitely unexpected.
– Roly
Sep 26 '13 at 20:37
as of version 1.4.1.0 as I can see it is allowed to assign void functions calls
– shabunc
Jan 25 '15 at 22:23
add a comment |
+1 - you can test this using:var rg: {(): void;} = ; rg.push(function():string {return "";}) var x = rg[0]();
in the TypeScript playground to see the behaviour in action. Changevoid
tostring
and it will allow the return value to be used.
– Fenton
Oct 6 '12 at 22:14
Okay it makes sense, but is a little counter intuitive, i.e. allowing to add a function that does not match the type, even if it is void in the definition.
– Peter StJ
Oct 7 '12 at 17:55
2
The spec also says "void is only related to the types Undefined, Null and Any", so I'm not sure the spec is consistent. Definitely unexpected.
– Roly
Sep 26 '13 at 20:37
as of version 1.4.1.0 as I can see it is allowed to assign void functions calls
– shabunc
Jan 25 '15 at 22:23
+1 - you can test this using:
var rg: {(): void;} = ; rg.push(function():string {return "";}) var x = rg[0]();
in the TypeScript playground to see the behaviour in action. Change void
to string
and it will allow the return value to be used.– Fenton
Oct 6 '12 at 22:14
+1 - you can test this using:
var rg: {(): void;} = ; rg.push(function():string {return "";}) var x = rg[0]();
in the TypeScript playground to see the behaviour in action. Change void
to string
and it will allow the return value to be used.– Fenton
Oct 6 '12 at 22:14
Okay it makes sense, but is a little counter intuitive, i.e. allowing to add a function that does not match the type, even if it is void in the definition.
– Peter StJ
Oct 7 '12 at 17:55
Okay it makes sense, but is a little counter intuitive, i.e. allowing to add a function that does not match the type, even if it is void in the definition.
– Peter StJ
Oct 7 '12 at 17:55
2
2
The spec also says "void is only related to the types Undefined, Null and Any", so I'm not sure the spec is consistent. Definitely unexpected.
– Roly
Sep 26 '13 at 20:37
The spec also says "void is only related to the types Undefined, Null and Any", so I'm not sure the spec is consistent. Definitely unexpected.
– Roly
Sep 26 '13 at 20:37
as of version 1.4.1.0 as I can see it is allowed to assign void functions calls
– shabunc
Jan 25 '15 at 22:23
as of version 1.4.1.0 as I can see it is allowed to assign void functions calls
– shabunc
Jan 25 '15 at 22:23
add a comment |
That looks like a bug. You should open a new work item for the issue
Did that, but given the above comment I guess this is intended. Not finding generics much use in TS so far...
– Roly
Sep 26 '13 at 20:39
add a comment |
That looks like a bug. You should open a new work item for the issue
Did that, but given the above comment I guess this is intended. Not finding generics much use in TS so far...
– Roly
Sep 26 '13 at 20:39
add a comment |
That looks like a bug. You should open a new work item for the issue
That looks like a bug. You should open a new work item for the issue
answered Oct 6 '12 at 17:38
Steven IckmanSteven Ickman
1,81197
1,81197
Did that, but given the above comment I guess this is intended. Not finding generics much use in TS so far...
– Roly
Sep 26 '13 at 20:39
add a comment |
Did that, but given the above comment I guess this is intended. Not finding generics much use in TS so far...
– Roly
Sep 26 '13 at 20:39
Did that, but given the above comment I guess this is intended. Not finding generics much use in TS so far...
– Roly
Sep 26 '13 at 20:39
Did that, but given the above comment I guess this is intended. Not finding generics much use in TS so far...
– Roly
Sep 26 '13 at 20:39
add a comment |
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%2f12761607%2ftypescript-void-return-type-converted-to-any-type%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