Why just conditionals?
Declarations could be useful in many other places, for example
foo(let bar = buz());
Why not just equate variable declarations to expression statements in the scope of this proposal?
What is the point of allowing declarations in these other places? A big difference with conditionals is that they create a new (nested) scope, whereas most other code does not.
foo(let bar = buz());
Why not just foo(buz)? What does allowing let/const add?
It could be used after, for example
foo((let bar = buz()) && bar.x && bar.y);
One more time - it's just an example. It can be useful in many other cases. For example, switch - here also block scoping like in if and while.
I'm not opposed to "extending" this proposal to switch as well, but I personally don't see it being as useful there as if/while, given that it's already necessary to provide some other value to compare against for each case (not including default, which I think would benefit the most from this, as then you could actually get the value out of the switch for further use inside a default), meaning that you have the equivalent value written as part of case and could use that instead. I do see value in reusing the same identifier in each case, though, so I'll keep this in mind.
As far as your example (which I understand is just an example), I personally find reading that to be extremely confusing and not immediately/obviously clear as to how it would work. One question that immediately pop into my head when seeing that is whether bar is scoped to foo (is it only visible until foo returns, but at the same time isn't actually visible to the body of foo)? Since there are no { ... }, my mind thinks that bar would be visible outside foo (but in the same scope as foo), which I don't think you are suggesting. The extra parenthesis around let bar = buz() (which I'm guessing is to distinguish it as a variable declaration, and wouldn't actually be required) just adds to that confusion.
I'd rather keep this proposal simple, as it's a fairly well established concept in some other languages as well. I'd like to discuss what I have proposed first, and once that has been decided (assuming it is accepted) then perhaps we can extend it to support your suggestion (see the Future Work section for other ideas).
One question that immediately pop into my head when seeing that is whether
baris scoped tofoo(is it only visible until foo returns, but at the same time isn't actually visible to the body offoo)?
It's not principal for me - it can be visible outside of foo for don't extend the scoping model.
The extra parenthesis around
let bar = buz()(which I'm guessing is to distinguish it as a variable declaration, and wouldn't actually be required)
Without those parentheses, the order of the operators will be broken - && executed before =.
As I understand, case like foo((let bar = buz()) && bar.x && bar.y) could (should) be solved by do expression proposal.
switch would be useful to have.
function foo(bar) {
switch (const type = typeof bar) {
case "string":
case "number":
return `This is a ${type} value!`;
default:
throw new TypeError(`I do not support ${type}!`);
}
}
I brought it up in the IRC at one point, https://freenode.logbot.info/tc39/20190903#c2616001