Signature of lambda return types in TypeScript

Viewed 21861

In the TypeScript below both functions are the same, except that I'm trying to explicitly declare the return type in demoTwo. The return type is a function which itself takes a function as input. My question is why do I have to give the parameter name represented by whyThis, given that it will never be used? The code will not compile without something in that position.

function demoOne() {
    return function(input: () => string) : void {
        var result = input();
        console.log("Foo:",result);
    }
}

function demoTwo(): (whyThis:() => string) => void {
    return function(input: () => string) : void {
        var result = input();
        console.log("Bar:",result);
    }
}

var sampleInput = () => "wibble";
demoOne()(sampleInput);
demoTwo()(sampleInput);

To be clear what I'm asking here's the equivalent code in Scala:

object Program {
  def demoTwo(): (() => String) => Unit = {
    def tmp(input: () => String): Unit = {
      val result = input()
      println("Bar: " + result)
    }
    return tmp
  }
  def main(args: Array[String]): Unit = {
    val sampleInput = () => "wibble"
    demoTwo()(sampleInput)
  }
}

If we set the declarations of demoTwo side by side we have:

function demoTwo(): (whyThis:() => string) => void { //TS
def demoTwo(): (() => String) => Unit = { //Scala

The only major difference is that TS requires something at the whyThis position and Scala does not. Why should this be the case?

3 Answers

In the section Function Type Expressions – Typescript Handbook they have a note about the syntax of, e.g. (a: string) => void:

Note that the parameter name is required. The function type (string) => void means “a function with a parameter named string of type any“!

Checking the grammar in typescript.ebnf (not official, took from SO answer), the identifier name is indeed mandatory:

// A parameter list can basically be defined by

Parameter-List ::= 
    RequiredParameterList
  | OptionalParameterList
  | RestParameter
  |  // omitting combinations


// All parameter types require an Identifier, then an optional TypeAnnotation

<RequiredParameterList> ::= RequiredParameter (comma RequiredParameter)*
<OptionalParameterList> ::= OptionalParameter (comma OptionalParameter)*
RequiredParameter ::= 
    [AccessLevel] Identifier [TypeAnnotation]
  | Identifier ':' ws-opt StringLiteral
OptionalParameter ::= 
    [AccessLevel] Identifier <'?'> [TypeAnnotation]
  | [AccessLevel] Identifier [TypeAnnotation] Initialiser
RestParameter ::= "..." Identifier [TypeAnnotation] ws-opt

I think an argument could be made to parse (() => string) => void as a function with a FunctionType argument, somehow considering an anonymous Identifier. Not sure how tricky the grammar would become.

Related