Skip to main content

函数

函数有两个应用类型的地方:参数(输入)和返回值(输出)。

¥Functions have two places where types are applied: parameters (input) and the return value (output).

1function concat(a: string, b: string): string {2  return a + b;3}4
5concat("foo", "bar"); // Works!6concat(true, false);  // Error!

使用推断,返回类型通常是可选的:

¥Using inference, return types are often optional:

1function concat(a: string, b: string) {2  return a + b;3}4
5const s: string = concat("foo", "bar"); // Works!

如果定义在我们可以从表达式上下文中获取类型的位置,则类型注释可以是可选的:

¥If defined where we can get the type from the context of the expression, type annotations can be optional:

1[1, 2, 3].map(x => x * x); // From the context, we know parameter `x` has type `number`

函数语法

¥Syntax of functions

函数分为三种形式,每种形式的语法略有不同。

¥There are three forms of functions that each have their own slightly different syntax.

函数声明

¥Function Declarations

1function func(str: string, bool?: boolean, ...nums: Array<number>): void {2  // ...3}

箭头函数

¥Arrow Functions

1let func = (str: string, bool?: boolean, ...nums: Array<number>): void => {2  // ...3};

函数类型

¥Function Types

1type T = (str: string, bool?: boolean, ...nums: Array<number>) => void;

你还可以选择省略参数名称。

¥You may also optionally leave out the parameter names.

1type T = (string, boolean | void, Array<number>) => void;

你可以将这些函数类型用于回调之类的用途。

¥You might use these functions types for something like a callback.

1function func(callback: (error: Error | null, value: string | null) => void) {2  // ...3}

类型参数

¥Type arguments

函数可以有类型参数:

¥Functions can have type arguments:

1function f<T>(x: T): Array<T> {2  return [x];3}4
5const g = <T>(x: T): Array<T> => [x];6
7type H = <T>(T) => Array<T>;

函数参数

¥Function Parameters

函数参数可以通过在参数名称后添加冒号 : 和后面的类型来具有类型。

¥Function parameters can have types by adding a colon : followed by the type after the name of the parameter.

1function func(param1: string, param2: boolean) {2  // ...3}

可选参数

¥Optional Parameters

你还可以通过在参数名称后面和冒号 : 之前添加问号 ? 来获得可选参数。

¥You can also have optional parameters by adding a question mark ? after the name of the parameter and before the colon :.

1function func(optionalValue?: string) {2  // ...3}

可选参数将接受缺失、undefined 或匹配的类型。但他们不会接受 null

¥Optional parameters will accept missing, undefined, or matching types. But they will not accept null.

1function func(optionalValue?: string) {2  // ...3}4
5func();          // Works.6func(undefined); // Works.7func("string");  // Works.8
9func(null);      // Error!

其余参数

¥Rest Parameters

JavaScript 还支持在参数列表末尾使用剩余参数或收集参数数组的参数。它们前面有一个省略号 ...

¥JavaScript also supports having rest parameters or parameters that collect an array of arguments at the end of a list of parameters. These have an ellipsis ... before them.

你还可以使用相同的语法但使用 Array 为其余参数添加类型注释。

¥You can also add type annotations for rest parameters using the same syntax but with an Array.

1function func(...args: Array<number>) {2  // ...3}

你可以将任意数量的参数传递到剩余参数中。

¥You can pass as many arguments as you want into a rest parameter.

1function func(...args: Array<number>) {2  // ...3}4
5func();        // Works.6func(1);       // Works.7func(1, 2);    // Works.8func(1, 2, 3); // Works.

注意:如果将类型注释添加到剩余参数,则它必须始终显式为 Array$ReadOnlyArray 类型。

¥Note: If you add a type annotation to a rest parameter, it must always explicitly be an Array of $ReadOnlyArray type.

this 参数

¥this parameter

JavaScript 中的每个函数都可以使用名为 this 的特殊上下文来调用。你可以使用任何你想要的上下文调用函数。Flow 允许你通过在函数参数列表的开头添加特殊参数来注释此上下文的类型:

¥Every function in JavaScript can be called with a special context named this. You can call a function with any context that you want. Flow allows you to annotate the type for this context by adding a special parameter at the start of the function's parameter list:

1function func<T>(this: { x: T }) : T {2  return this.x;3}4
5const num: number = func.call({x : 42});6const str: string = func.call({x : 42}); // Error!

该参数在运行时不起作用,并且在 Flow 转换为 JavaScript 时与类型一起被删除。如果存在,this 参数必须始终出现在函数参数列表的最开头,并且必须有注释。此外,箭头函数 可能没有 this 参数注释,因为这些函数在定义站点而不是调用站点绑定其 this 参数。

¥This parameter has no effect at runtime, and is erased along with types when Flow is transformed into JavaScript. When present, this parameters must always appear at the very beginning of the function's parameter list, and must have an annotation. Additionally, arrow functions may not have a this parameter annotation, as these functions bind their this parameter at the definition site, rather than the call site.

如果未提供显式 this 参数,Flow 将尝试根据使用情况推断参数。如果函数体中未提及 this,Flow 将为其 this 参数推断 mixed

¥If an explicit this parameter is not provided, Flow will attempt to infer one based on usage. If this is not mentioned in the body of the function, Flow will infer mixed for its this parameter.

函数返回

¥Function Returns

函数返回还可以使用冒号 : 添加类型,后跟参数列表后面的类型。

¥Function returns can also add a type using a colon : followed by the type after the list of parameters.

1function func(): number {2  return 1;3}

返回类型确保函数的每个分支返回相同的类型。这可以防止你在某些情况下意外地不返回值。

¥Return types ensure that every branch of your function returns the same type. This prevents you from accidentally not returning a value under certain conditions.

1function func(): boolean {2  if (Math.random() > 0.5) {3    return true;4  }5}

异步函数隐式返回一个 Promise,因此返回类型必须始终为 Promise

¥Async functions implicitly return a promise, so the return type must always be a Promise.

1async function func(): Promise<number> {2  return 123;3}

谓词函数

¥Predicate Functions

警告

谓词函数已弃用,将在未来的版本中删除。请改用 类型保护

¥Predicate functions are deprecated and will be removed in a future version. Use type guards instead.

有时你需要将条件从 if 语句移至函数中:

¥Sometimes you will want to move the condition from an if statement into a function:

1function concat(a: ?string, b: ?string): string {2  if (a != null && b != null) {3    return a + b;4  }5  return '';6}

但是,Flow 在以下代码中会出错:

¥However, Flow will error in the code below:

1function truthy(a: ?string, b: ?string): boolean {2  return a != null && b != null;3}4
5function concat(a: ?string, b: ?string): string {6  if (truthy(a, b)) {7    return a + b; // Error!8  }9  return '';10}

这是因为从 truthy 函数返回时,ab 的细化信息丢失为 string 而不是 ?string

¥This is because the refinement information of a and b as string instead of ?string is lost when returning from the truthy function.

你可以通过使用 %checks 注释将 truthy 设为谓词函数来解决此问题,如下所示:

¥You can fix this by making truthy a predicate function, by using the %checks annotation like so:

1function truthy(a: ?string, b: ?string): boolean %checks {2  return a != null && b != null;3}4
5function concat(a: ?string, b: ?string): string {6  if (truthy(a, b)) {7    return a + b;8  }9  return '';10}

谓词函数的限制

¥Limitations of predicate functions

这些谓词函数的主体必须是表达式(即不支持局部变量声明)。但可以在谓词函数内调用其他谓词函数。例如:

¥The body of these predicate functions need to be expressions (i.e. local variable declarations are not supported). But it's possible to call other predicate functions inside a predicate function. For example:

1function isString(y: mixed): %checks {2  return typeof y === "string";3}4
5function isNumber(y: mixed): %checks {6  return typeof y === "number";7}8
9function isNumberOrString(y: mixed): %checks {10  return isString(y) || isNumber(y);11}12
13function foo(x: string | number | Array<mixed>): string | number {14  if (isNumberOrString(x)) {15    return x + x;16  } else {17    return x.length; // no error, because Flow infers that x can only be an array18  }19}20
21foo('a');22foo(5);23foo([]);

另一个限制是可以编码的谓词范围。谓词函数中支持的细化必须直接引用作为参数传递给相应调用的值。

¥Another limitation is on the range of predicates that can be encoded. The refinements that are supported in a predicate function must refer directly to the value that is passed in as an argument to the respective call.

例如,考虑内联细化

¥For example, consider the inlined refinement

1declare const obj: {n?: number};2
3if (obj.n != null) {4  const n: number = obj.n;5}

在这里,Flow 会让你将 obj.n?number 细化到 number。请注意,这里的细化是针对 obj 的属性 n,而不是 obj 本身。

¥Here, Flow will let you refine obj.n from ?number to number. Note that the refinement here is on the property n of obj, rather than obj itself.

如果你尝试创建谓词函数来编码相同的条件,则以下细化将失败

¥If you tried to create a predicate function to encode the same condition, then the following refinement would fail

1function bar(a: {n?: number, ...}): %checks {2  return a.n != null;3}4
5declare const obj: {n?: number};6
7if (bar(obj)) {8  const n: number = obj.n; // Error9}

这是因为 bar 支持的唯一改进是 obj 本身。

¥This is because the only refinements supported through bar would be on obj itself.

可调用对象

¥Callable Objects

可以键入可调用对象,例如:

¥Callable objects can be typed, for example:

1type CallableObj = {2  (number, number): number,3  bar: string,4  ...5};6
7function add(x: number, y: number) {8  return x + y;9}10
11add.bar = "hello world";12
13add as CallableObj;

一般来说,如果函数是函数声明或 const f = () => ... 形式的简单变量声明,则可以为其分配属性。属性必须以 f.prop = <expr>; 格式分配,在与函数定义相同的语句列表中(即无条件)。

¥In general, functions can have properties assigned to them if they are function declarations, or simple variable declarations of the form const f = () => .... The properties must be assigned in the format f.prop = <expr>;, in the same statement list as the function definition (i.e. not conditionally).

请注意,表示分配给函数的静态属性的对象是不精确的。

¥Note that the object representing the static properties assigned to the function is inexact.

重载函数

¥Overloaded functions

你可以使用交集类型来定义 重载函数类型

¥You can use intersection types to define overloaded function types:

1declare const fn:2  & ((x: 'string') => string)3  & ((x: 'number') => number)4
5const s: string = fn('string');6const n: number = fn('number');

任何函数

¥Any function

如果你想指定允许任何功能,并且不关心它是什么,你可以使用此模式:

¥If you want to specify you want to allow any function, and do not care what it is, you can use this pattern:

1function useCallback<T: (...$ReadOnlyArray<empty>) => mixed>(2  callback: T,3  inputs: ?$ReadOnlyArray<mixed>,4): T {5  return callback;6}7useCallback((x: string) => true); // OK8useCallback((x: number) => [1]); // OK

你可以使用类型参数来捕获参数和返回类型,以进行更复杂的转换:

¥You could use type arguments to capture the arguments and return type, to do more complicated transformations:

1function func<TArgs: $ReadOnlyArray<mixed>, TReturn>(2  callback: (...TArgs) => TReturn,3): (boolean, ...TArgs) => Array<TReturn> {4  return (b, ...args): Array<TReturn> => {5    if (b) {6      return [callback(...args)];7    } else {8      return [];9    }10  };11}12
13const f: (boolean, string, number) => Array<string> =14  func((x: string, y: number) => x.slice(y)); // OK

类型 Function 只是 any 的别名,并且是不安全的。你可以使用 不明类型棉绒 禁止在代码中使用它。

¥The type Function is just an alias for any, and is unsafe. You can ban its use in your code with the unclear-type lint.