Skip to main content

变量声明

当你声明一个新变量时,你可以选择声明它的类型。

¥When you are declaring a new variable, you may optionally declare its type.

JavaScript 具有三种声明局部变量的方式:

¥JavaScript has three ways of declaring local variables:

  • var - 声明一个变量,可以选择指定一个值。(MDN)

    ¥var - declares a variable, optionally assigning a value. (MDN)

  • let - 声明一个块作用域的变量,可以选择分配一个值。(MDN)

    ¥let - declares a block-scoped variable, optionally assigning a value. (MDN)

  • const - 声明一个块作用域变量,分配一个不能重新分配的值。(MDN)

    ¥const - declares a block-scoped variable, assigning a value that cannot be re-assigned. (MDN)

在 Flow 中,它们分为两组:

¥In Flow these fall into two groups:

  • letvar - 可以重新分配的变量。

    ¥let and var - variables that can be reassigned.

  • const - 不能重新赋值的变量。

    ¥const - variables that cannot be reassigned.

1var varVariable = 1;2let letVariable = 1;3const constVariable = 1;4
5varVariable = 2;   // Works!6letVariable = 2;   // Works!7constVariable = 2; // Error!

const

由于 const 变量不能在以后重新分配,所以它相当简单。

¥Since a const variable cannot be re-assigned at a later time it is fairly simple.

Flow 可以根据你分配给它的值推断类型,或者你可以为其提供类型。

¥Flow can either infer the type from the value you are assigning to it or you can provide it with a type.

1const foo /* : number */ = 1;2const bar: number = 2;

varlet

¥var and let

0.186

{#toc-var-and-let} 由于 varlet 可以重新分配,因此你还需要了解更多规则。

¥{#toc-var-and-let} Since var and let can be re-assigned, there's a few more rules you'll need to know about.

当你提供类型时,你将能够重新分配该值,但它必须始终是兼容的类型。

¥When you provide a type, you will be able to re-assign the value, but it must always be of a compatible type.

1let foo: number = 1;2foo = 2;   // Works!3foo = "3"; // Error!

当变量没有注释时,Flow 会根据其初始值设定项或初始赋值推断出精确的类型。对该变量的所有后续赋值都将受此类型的约束。本节显示一些示例,说明 Flow 如何确定推断未注释变量的类型。

¥When the variable has no annotation, Flow infers a precise type based on their initializer or initial assignment. All subsequent assignments to that variable will be constrained by this type. This section shows some examples of how Flow determines what type an unannotated variable is inferred to have.

如果你希望变量具有与 Flow 为其推断的类型不同的类型,你始终可以在变量的声明中添加类型注释。这将覆盖本页讨论的所有内容!

¥If you want a variable to have a different type than what Flow infers for it, you can always add a type annotation to the variable’s declaration. That will override everything discussed in this page!

在声明处初始化的变量

¥Variables initialized at their declarations

未注释变量的常见情况非常简单:当使用不是字面量 null 的初始值设定项声明变量时,该变量将从那时起具有初始值设定项的类型,并且将来对该变量的写入将受该类型的约束。

¥The common case for unannotated variables is very straightforward: when a variable is declared with an initializer that is not the literal null, that variable will from then on have the type of the initializer, and future writes to the variable will be constrained by that type.

1import * as React from 'react';2
3type Props = $ReadOnly<{ prop: string }>;4
5declare var x: number;6declare var y: number;7declare var props: Props;8
9let product = Math.sqrt(x) + y;10// `product` has type `number`11
12let Component = ({prop}: Props): React.Node => { return <div/> }13// `Component` has type`React.ComponentType<Props>`14
15let element = <Component {...props} />16// `element` has type `React.Element<React.ComponentType<Props>>`17
18/* Let's define a new component */19
20type OtherProps = $ReadOnly<{ ...Props, extra_prop: number }>;21declare var OtherComponent: (OtherProps) => React.Node;22declare var other_props: OtherProps23
24/* Any subsequent assignments to `product`, `Component`, or `element` will be25
26 * checked against the types that Flow infers for the initializers, and if27
28 * conflicting types are assigned, Flow will signal an error. */29
30product = "Our new product is...";31Component = ({prop}: OtherProps): React.Node => { return <div/> };32element = <OtherComponent {...other_props} />;

如果你希望对这些示例进行类型检查,并且让 Flow 认识到可以将不同类型的值写入这些变量,则必须在其声明中添加反映这种更通用类型的类型注释:

¥If you want these examples to typecheck, and for Flow to realize that different kinds of values can be written to these variables, you must add a type annotation reflecting this more general type to their declarations:

let product: number | string = ...
let Component: mixed = ... // No good type to represent this! Consider restructuring
let element: React.Node = ...

未使用初始值设定项声明的变量

¥Variables declared without initializers

通常,变量是在没有初始化器的情况下声明的。在这种情况下,Flow 将尝试选择 "第一的" 赋值或对变量的赋值来定义其类型。"第一的" 这里意味着从上到下以及从较近的范围到较深的范围 - 我们将尝试选择在与变量声明相同的函数范围内发生的赋值,并且仅在找不到时才查看嵌套函数内部 任何本地作业:

¥Often variables are declared without initializers. In such cases, Flow will try to choose the "first" assignment or assignments to the variable to define its type. "First" here means both top-to-bottom and nearer-scope to deeper-scope—we’ll try to choose an assignment that happens in the same function scope as the variable’s declaration, and only look inside nested functions if we don’t find any assignments locally:

1let topLevelAssigned;2function helper() {3  topLevelAssigned = 42; // Error: `topLevelAssigned` has type `string`4}5topLevelAssigned = "Hello world"; // This write determines the var's type6topLevelAssigned = true; // Error: `topLevelAssigned` has type `string`

如果由于 ifswitch 语句而存在两个或多个可能的 "第一个任务,",则它们都会计数 — 这是 Flow 仍会推断变量类型并集的少数方法之一:

¥If there are two or more possible "first assignments," due to an if- or switch-statement, they’ll both count—this is one of the few ways that Flow will still infer unions for variable types:

1let myNumberOrString;2declare var condition: boolean;3if (condition) {4  myNumberOrString = 42; // Determines type5} else {6  myNumberOrString = "Hello world"; // Determines type7}8myNumberOrString = 21; // fine, compatible with type9myNumberOrString = "Goodbye"; // fine, compatible with type10myNumberOrString = false; // Error: `myNumberOrString` has type `number | string`

然而,这只适用于在两个分支中写入变量时。如果只有一个分支包含写入,则该写入随后将成为变量的类型(尽管 Flow 仍会检查以确保变量已明确初始化):

¥This only applies when the variable is written to in both branches, however. If only one branch contains a write, that write becomes the type of the variable afterwards (though Flow will still check to make sure that the variable is definitely initialized):

1let oneBranchAssigned;2declare var condition: boolean;3if (condition) {4  oneBranchAssigned = "Hello world!";5}6oneBranchAssigned.toUpperCase(); // Error: `oneBranchAssigned` may be uninitialized7oneBranchAssigned = 42; // Error: `oneBranchAssigned` has type `string`

变量初始化为 null

¥Variables initialized to null

最后,变量的类型由其第一个赋值确定的一般原则的一个例外是当变量被初始化为(或其第一个赋值)字面量值 null 时。在这种情况下,下一个非空赋值(使用与上面相同的规则)确定变量的其余类型,并且变量的整体类型成为 null 和后续赋值类型的联合。这支持常见模式,其中变量以 null 开头,然后被其他类型的值分配:

¥Finally, the one exception to the general principle that variable’s types are determined by their first assignment(s) is when a variable is initialized as (or whose first assignment is) the literal value null. In such cases, the next non-null assignment (using the same rules as above) determines the rest of the variable’s type, and the overall type of the variable becomes a union of null and the type of the subsequent assignment. This supports the common pattern where a variable starts off as null before getting assigned by a value of some other type:

1function findIDValue<T>(dict: {[key: string]: T}): T {2  let idVal = null; // initialized as `null`3  for (const key in dict) {4    if (key === 'ID') {5      idVal = dict[key]; // Infer that `idVal` has type `null | T`6    }7  }8  if (idVal === null) {9    throw new Error("No entry for ID!");10  }11  return idVal;12}

捕获变量

¥Catch variables

0.197

如果 catch 变量没有注释,则其默认类型为 any

¥If a catch variable does not have an annotation, its default type is any.

你可以选择使用 mixedany 对其进行注释。例如。

¥You can optionally annotate it with exactly mixed or any. E.g.

1try {2} catch (e: mixed) {3  if (e instanceof TypeError) {4    e as TypeError; // OK5  } else if (e instanceof Error) {6    e as Error; // OK7  } else {8    throw e;9  }10}

通过使用 mixed,你可以提高安全性和 Flow 覆盖范围,但代价是增加运行时检查。

¥By using mixed, you can improve your safety and Flow coverage, at the trade-off of increased runtime checks.

当没有注释时,你可以通过将 use_mixed_in_catch_variables 选项设置为 true 来更改 catch 变量的默认类型。

¥You can change the default type of catch variables when there is no annotation by setting the use_mixed_in_catch_variables option to true.