映射类型
Flow 的映射类型允许你转换对象类型。它们对于对对象上的复杂运行时操作进行建模非常有用。
¥Flow's mapped types allow you to transform object types. They are useful for modeling complex runtime operations over objects.
基本用法
¥Basic Usage
映射类型的语法与索引对象类型类似,但使用 in
关键字:
¥Mapped Types have syntax similar to indexed object types but use the in
keyword:
1type O = {foo: number, bar: string};2
3type Methodify<T> = () => T;4
5type MappedType = {[key in keyof O]: Methodify<O[key]>};
在此示例中,MappedType
具有 O
中的所有键以及由 Methoditfy<O[key]>
转换的所有值类型。创建属性时,key
变量会替换 O
中的每个键,因此该类型的计算结果为:
¥In this example, MappedType
has all of the keys from O
with all of the value types transformed by
Methoditfy<O[key]>
. The key
variable is substituted for each key in O
when creating the property, so
this type evaluates to:
{
foo: Methodify<O['foo']>,
bar: Methodify<O['bar']>,
}
= {
foo: () => number,
bar: () => string,
}
映射类型源
¥Mapped Type Sources
我们将 in
关键字后面的类型称为映射类型的源。映射类型的源必须是 string | number | symbol
的子类型:
¥We call the type that comes after the in
keyword the source of the mapped type. The source of
a mapped type must be a subtype of string | number | symbol
:
1type MappedType = {[key in boolean]: number}; // ERROR!
通常,你需要基于另一个对象类型创建映射类型。在这种情况下,你应该使用内联 keyof
编写映射类型:
¥Typically, you'll want to create a mapped type based on another object type. In this case, you
should write your mapped type using an inline keyof
:
1type GetterOf<T> = () => T;2type Obj = {foo: number, bar: string};3type MappedObj = {[key in keyof Obj]: GetterOf<Obj[key]>};
注意:
keyof
目前仅在映射类型中内联工作。尚未提供对keyof
的全面支持。¥NOTE:
keyof
only works inline in mapped types for now. Full support forkeyof
is not yet available.
但你不需要使用对象来生成映射类型。你还可以使用字符串字面量类型的联合来表示对象类型的键:
¥But you do not need to use an object to generate a mapped type. You can also use a union of string literal types to represent the keys of an object type:
1type Union = 'foo' | 'bar' | 'baz';2type MappedType = {[key in Union]: number};3// = {foo: number, bar: number, baz: number};
重要的是,当使用字符串字面量时,联合会折叠为单个对象类型:
¥Importantly, when using string literals the union is collapsed into a single object type:
1type MappedTypeFromKeys<Keys: string> = {[key in Keys]: number};2type MappedFooAndBar = MappedTypeFromKeys<'foo' | 'bar'>;3// = {foo: number, bar: number}, not {foo: number} | {bar: number}
如果你在映射类型的源中使用像 number
或 string
这样的类型,那么 Flow 将创建一个索引器:
¥If you use a type like number
or string
in the source of your mapped type then Flow will create
an indexer:
1type MappedTypeFromKeys<Keys: string> = {[key in Keys]: number};2type MappedFooAndBarWithIndexer = MappedTypeFromKeys<'foo' | 'bar' | string>;3// = {foo: number, bar: number, [string]: number}
分配映射类型
¥Distributive Mapped Types
当映射类型使用内联 keyof
或由 $Keys
绑定的类型参数时,Flow 会将映射类型分布在对象类型的联合上。
¥When the mapped type uses an inline keyof
or a type parameter bound by a $Keys
Flow will distribute the mapped type over unions of object types.
例如:
¥For example:
1// This mapped type uses keyof inline2type MakeAllValuesNumber<O: {...}> = {[key in keyof O]: number};3type ObjWithFoo = {foo: string};4type ObjWithBar = {bar: string};5
6type DistributedMappedType = MakeAllValuesNumber<7 | ObjWithFoo8 | ObjWithBar9>; // = {foo: number} | {bar: number};10
11// This mapped type uses a type parameter bound by $Keys12type Pick<O: {...}, Keys: $Keys<O>> = {[key in Keys]: O[key]};13type O1 = {foo: number, bar: number};14type O2 = {bar: string, baz: number};15type PickBar = Pick<O1 | O2, 'bar'>; // = {bar: number} | {bar: string};
分布式映射类型也将分布在 null
和 undefined
上:
¥Distributive mapped types will also distribute over null
and undefined
:
1type Distributive<O: ?{...}> = {[key in keyof O]: O[key]};2type Obj = {foo: number};3type MaybeMapped = Distributive<?Obj>;// = ?{foo: number}4null as MaybeMapped; // OK5undefined as MaybeMapped; // OK6({foo: 3}) as MaybeMapped; // OK
属性修饰符
¥Property Modifiers
你还可以在映射类型中添加 +
或 -
方差修饰符以及可选修饰符 ?
:
¥You can also add +
or -
variance modifiers and the optionality modifier ?
in mapped types:
1type O = {foo: number, bar: string}2type ReadOnlyPartialO = {+[key in keyof O]?: O[key]}; // = {+foo?: number, +bar?: string};
当未提供方差或可选性修饰符并且映射类型是分布式时,方差和可选性由输入对象确定:
¥When no variance nor optionality modifiers are provided and the mapped type is distributive, the variance and optionality are determined by the input object:
1type O = {+foo: number, bar?: string};2type Mapped = {[key in keyof O]: O[key]}; // = {+foo: number, bar?: string}
否则,当不存在属性修饰符时,这些属性是可读写的并且是必需的:
¥Otherwise, the properties are read-write and required when no property modifiers are present:
1type Union = 'foo' | 'bar' | 'baz';2type MappedType = {[key in Union]: number};3// = {foo: number, bar: number, baz: number};
注意:Flow 尚不支持删除方差或可选性修饰符。
¥NOTE: Flow does not yet support removing variance or optionality modifiers.
数组上的映射类型
¥Mapped Type on Arrays
≥0.246{#toc-mapped-type-on-arrays}
映射类型也适用于数组或元组输入。如果映射类型的形式为
¥Mapped type also works on array or tuple inputs. If the mapped type is in the form of
{[K in keyof <type_1>]: <type_2>}
然后 type_1
可以是数组或元组类型。
¥then type_1
is allowed to be an array or tuple type.
如果你想映射元组的元素,此功能将特别有用:
¥This feature will be especially useful if you want to map over elements of a tuple:
1type Tuple = [+a: number, b?: string];2type MappedTuple = {[K in keyof Tuple]: Tuple[K] extends number ? boolean : string};3const a: MappedTuple[0] = true;4const b: MappedTuple[1] = '';5'' as MappedTuple[0] // error6false as MappedTuple[1] // error7declare const mapped: MappedTuple;8mapped[0] = true; // error: cannot-write
目前,数组输入上唯一支持的属性修饰符是可选修饰符 ?
。
¥For now, the only supported property modifier on array input is the optionality modifier ?
.
1type Tuple = [+a: number, b?: string];2type Supported = {[K in keyof Tuple]?: string};3type Unsupported1 = {+[K in keyof Tuple]: string};4type Unsupported2 = {-[K in keyof Tuple]: string};
采纳
¥Adoption
要使用映射类型,你需要升级基础架构以使其支持语法:
¥To use mapped types, you need to upgrade your infrastructure so that it supports the syntax:
flow
和flow-parser
:0.210.0.在 v0.210.0 到 v0.211.1 之间,你需要在 .flowconfig 中显式启用它,在[options]
标题下添加mapped_type=true
。¥
flow
andflow-parser
: 0.210.0. Between v0.210.0 to v0.211.1, you need to explicitly enable it in your .flowconfig, under the[options]
heading, addmapped_type=true
.prettier
:3使用
babel-plugin-syntax-hermes-parser
babel
。请参阅 我们的 Babel 指南 了解设置说明。¥
babel
withbabel-plugin-syntax-hermes-parser
. See our Babel guide for setup instructions.使用
hermes-eslint
eslint
。请参阅 我们的 ESLint 指南 了解设置说明。¥
eslint
withhermes-eslint
. See our ESLint guide for setup instructions.