在下面的TypeScript中,两个函数都是相同的,除了我试图在 demoTwo 中显式声明返回类型。返回类型是一个本身将函数作为输入的函数。我的问题是为什么我必须给出 whyThis 所代表的参数名称,因为它永远不会被使用?如果没有该位置的东西,代码将无法编译。
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);
要清楚我在这里问的是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)
}
}
如果我们并排设置 demoTwo 的声明,我们有:
function demoTwo(): (whyThis:() => string) => void { //TS
def demoTwo(): (() => String) => Unit = { //Scala
唯一的主要区别是TS在 whyThis 位置需要一些东西而Scala不需要。为什么会出现这种情况?
答案 0 :(得分:3)
打字稿中的所有函数参数都需要有一个名称,无论您是否决定使用它们。你要添加的是调用签名,这是在运行时没有使用但在编写代码时会帮助你的东西。
如果您查看两个示例生成的javascript文件,它们都将输出完全相同的代码:
function demoOne() {
return function (input) {
var result = input();
console.log("Foo:", result);
};
}
function demoTwo() {
return function (input) {
var result = input();
console.log("Bar:", result);
};
}
编辑:所以你是正确的,因为在运行时从不使用参数,但是这些参数确实在编译期间显示(取决于你的编辑器)。如果不添加调用签名,编辑器将从运行时参数中推断出一个,并在编译期间显示它。
您可以认为您将签名称为一种向其他人传达您的代码的使用方式以及参数所代表的内容的方式,这些代码对于将使用您的代码的人来说非常容易理解。
以下是Visual Studio在功能上方显示的内容,这些代码定义在调用这些函数时也会显示在VSCode和其他编辑器中:
演示一:
演示二:
答案 1 :(得分:2)
我认为混淆源于签名的定义方式。请注意下面的3个签名
(number) => Void
(x : number) => Void
(_ : number) => Void
最后两个是带有类型编号参数的void函数的签名。然而,第一个是一个带有名称编号的任意类型的argumnet的函数。因此语言需要一个名称后跟一个类型,如果省略该类型,则假定为Any类型。
所以,
(() => string) => void
无效为'()=> string'不是一个有效的名称,编译器因此试图解析它而感到困惑。
最短的表格将使用'_:type'。
但是我同意这个名称被省略并且只使用类型或名称是可选的更好。我不确定他们为什么做出那个设计决定,也许是为了避免与现有的JavaScript箭头功能混淆(没有类型)。
答案 2 :(得分:0)
在 Function Type Expressions – Typescript Handbook 部分,他们有一个关于语法的注释,例如(a: string) => void
:
请注意,参数名称是必需的。函数类型(字符串) => void 表示“一个函数,其参数名为字符串,类型为 any”!
检查 typescript.ebnf 中的语法(非官方,取自 SO answer),标识符名称确实是必需的:
// 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
我认为可以将 (() => string) => void
解析为带有 FunctionType
参数的函数,以某种方式考虑匿名 Identifier
。不确定语法会变得多么棘手。