Skip to main content

子集和子类型

什么是子类型?

¥What is a subtype?

numberbooleanstring 这样的类型描述了一组可能的值。number 描述了每个可能的数字,因此单个数字(例如 42)将是 number 类型的子类型。相反,number42 类型的超类型。

¥A type like number, boolean, or string describes a set of possible values. A number describes every possible number, so a single number (such as 42) would be a subtype of the number type. Conversely, number would be a supertype of the type 42.

如果我们想知道一种类型是否是另一种类型的子类型,我们需要查看这两种类型的所有可能值,并确定另一种类型是否具有这些值的子集。

¥If we want to know whether one type is the subtype of another, we need to look at all the possible values for both types and figure out if the other has a subset of the values.

例如,如果我们有一个描述数字 1 到 3 的 TypeA字面量类型联合),以及描述数字 1 到 5 的 TypeBTypeA 将被视为 TypeB 的子类型,因为 TypeATypeB 的子集。

¥For example, if we had a TypeA which described the numbers 1 through 3 (a union of literal types), and a TypeB which described the numbers 1 through 5: TypeA would be considered a subtype of TypeB, because TypeA is a subset of TypeB.

1type TypeA = 1 | 2 | 3;2type TypeB = 1 | 2 | 3 | 4 | 5;

考虑描述字符串的 TypeLetters:"A"、"B"、"C" 和 TypeNumbers 描述了这些数字:1、2、3。它们都不是另一个的子类型,因为它们各自包含一组完全不同的值。

¥Consider a TypeLetters which described the strings: "A", "B", "C", and a TypeNumbers which described the numbers: 1, 2, 3. Neither of them would be a subtype of the other, as they each contain a completely different set of values.

1type TypeLetters = "A" | "B" | "C";2type TypeNumbers =  1  |  2  |  3;

最后,如果我们有一个 TypeA 描述数字 1 到 3,还有一个 TypeB 描述数字 3 到 5。他们中的任何一个都不会是另一个的子类型。尽管它们都有 3 和描述数字,但它们都有一些独特的项目。

¥Finally, if we had a TypeA which described the numbers 1 through 3, and a TypeB which described the numbers 3 through 5. Neither of them would be a subtype of the other. Even though they both have 3 and describe numbers, they each have some unique items.

1type TypeA = 1 | 2 | 3;2type TypeB = 3 | 4 | 5;

什么时候使用子类型?

¥When are subtypes used?

Flow 所做的大部分工作是将类型相互进行比较。

¥Most of the work that Flow does is comparing types against one another.

例如,为了知道你是否正确调用了函数,Flow 需要将你传递的参数与函数期望的参数进行比较。

¥For example, in order to know if you are calling a function correctly, Flow needs to compare the arguments you are passing with the parameters the function expects.

这通常意味着要确定你传入的值是否是你期望的值的子类型。

¥This often means figuring out if the value you are passing in is a subtype of the value you are expecting.

因此,如果你编写一个需要数字 1 到 5 的函数,则该集合的任何子类型都是可接受的。

¥So if you write a function that expects the numbers 1 through 5, any subtype of that set will be acceptable.

1function f(param: 1 | 2 | 3 | 4 | 5) {2  // ...3}4
5declare const oneOrTwo: 1 |  2; // Subset of the input parameters type.6declare const fiveOrSix: 5 | 6; // Not a subset of the input parameters type.7
8f(oneOrTwo); // Works!9f(fiveOrSix); // Error!

复杂类型的子类型

¥Subtypes of complex types

Flow 需要比较的不仅仅是原始值集,它还需要能够比较对象、函数以及语言中出现的所有其他类型。

¥Flow needs to compare more than just sets of primitive values, it also needs to be able to compare objects, functions, and every other type that appears in the language.

对象的子类型

¥Subtypes of objects

你可以开始通过键来比较两个对象。如果一个对象包含另一个对象的所有键,那么它可能是一个子类型。

¥You can start to compare two objects by their keys. If one object contains all the keys of another object, then it may be a subtype.

例如,如果我们有一个包含密钥 fooObjectA,以及包含密钥 foobarObjectB。如果 ObjectA 不精确,那么 ObjectB 可能是 ObjectA 的子类型。

¥For example, if we had an ObjectA which contained the key foo, and an ObjectB which contained the keys foo and bar. Then it's possible that ObjectB is a subtype of ObjectA, if ObjectA is inexact.

1type ObjectA = {foo: string, ...};2type ObjectB = {foo: string, bar: number};3
4let objectB: ObjectB = {foo: 'test', bar: 42};5let objectA: ObjectA = objectB; // Works!

但我们还需要比较值的类型。如果两个对象都有一个键 foo,但一个是 number,另一个是 string,那么其中一个就不会是另一个的子类型。

¥But we also need to compare the types of the values. If both objects had a key foo but one was a number and the other was a string, then one would not be the subtype of the other.

1type ObjectA = {foo: string, ...};2type ObjectB = {foo: number, bar: number};3
4let objectB: ObjectB = { foo: 1, bar: 2 };5let objectA: ObjectA = objectB; // Error!

如果对象上的这些值碰巧是其他对象,我们就必须将它们相互比较。我们需要递归地比较每个值,直到我们可以确定是否有子类型。

¥If these values on the object happen to be other objects, we would have to compare those against one another. We need to compare every value recursively until we can decide if we have a subtype or not.

函数的子类型

¥Subtypes of functions

函数的子类型化规则更加复杂。到目前为止,我们已经看到,如果 B 包含 A 的所有可能值,则 AB 的子类型。对于函数来说,尚不清楚这种关系如何应用。为简化起见,如果可以在需要使用 B 类型的函数的任何地方使用 A 类型的函数,则可以将函数类型 A 视为函数类型 B 的子类型。

¥Subtyping rules for functions are more complicated. So far, we've seen that A is a subtype of B if B contains all possible values for A. For functions, it's not clear how this relationship would apply. To simplify things, you can think of a function type A as being a subtype of a function type B if functions of type A can be used wherever a function of type B is expected.

假设我们有一个函数类型和一些函数。哪些函数可以在需要给定函数类型的代码中安全地使用?

¥Let's say we have a function type and a few functions. Which of the functions can be used safely in code that expects the given function type?

1type FuncType = (1 | 2) => "A" | "B";2
3declare function f1(1 | 2): "A" | "B" | "C";4declare function f2(1 | null): "A" | "B";5declare function f3(1 | 2 | 3): "A";6
7f1 as FuncType; // Error8f2 as FuncType; // Error9f3 as FuncType; // Works!
  • f1 可以返回 FuncType 永远不会返回的值,因此如果使用 f1,依赖于 FuncType 的代码可能不安全。它的类型不是 FuncType 的子类型。

    ¥f1 can return a value that FuncType never does, so code that relies on FuncType might not be safe if f1 is used. Its type is not a subtype of FuncType.

  • f2 无法处理 FuncType 处理的所有参数值,因此依赖 FuncType 的代码无法安全地使用 f2。它的类型也不是 FuncType 的子类型。

    ¥f2 can't handle all the argument values that FuncType does, so code that relies on FuncType can't safely use f2. Its type is also not a subtype of FuncType.

  • f3 可以接受 FuncType 的所有参数值,并且只返回 FuncType 的值,因此它的类型是 FuncType 的子类型。

    ¥f3 can accept all the argument values that FuncType does, and only returns values that FuncType does, so its type is a subtype of FuncType.

一般来说,函数子类型化规则是这样的:当且仅当 B 的输入是 A 的超集,并且 B 的输出是 A 的子集时,函数类型 B 是函数类型 A 的子类型。子类型必须至少接受与其父类型相同的输入,并且必须最多返回相同的输出。

¥In general, the function subtyping rule is this: a function type B is a subtype of a function type A if and only if B's inputs are a superset of A's, and B's outputs are a subset of A's. The subtype must accept at least the same inputs as its parent, and must return at most the same outputs.

在输入和输出上应用子类型规则的方向的决定由 方差 控制,这是下一节的主题。

¥The decision of which direction to apply the subtyping rule on inputs and outputs is governed by variance, which is the topic of the next section.