映射类型
Flow 的映射类型允许您转换对象类型。它们对于对对象进行复杂运行时操作建模很有用。
基本用法
映射类型具有类似于索引对象类型的语法,但使用 in
关键字
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
中的每个键,因此此类型评估为
{
foo: Methodify<O['foo']>,
bar: Methodify<O['bar']>,
}
= {
foo: () => number,
bar: () => string,
}
映射类型源
我们将 in
关键字后面的类型称为映射类型的源。映射类型的源必须是 string | number | symbol
的子类型
1type MappedType = {[key in boolean]: number}; // ERROR!
1:28-1:34: Cannot instantiate mapped type [1] because boolean [2] is incompatible with `string | number | symbol`, so it cannot be used to generate keys for mapped type [1]. [incompatible-type]
通常,您希望基于另一个对象类型创建映射类型。在这种情况下,您应该使用内联 keyof
编写映射类型
1type GetterOf<T> = () => T;2type Obj = {foo: number, bar: string};3type MappedObj = {[key in keyof Obj]: GetterOf<Obj[key]>};
注意:
keyof
目前仅在映射类型中内联使用。keyof
的完全支持尚未提供。
但是,您不需要使用对象来生成映射类型。您还可以使用字符串字面量类型的联合来表示对象类型的键
1type Union = 'foo' | 'bar' | 'baz';2type MappedType = {[key in Union]: number};3// = {foo: number, bar: number, baz: number};
重要的是,当使用字符串字面量时,联合将折叠成一个单个对象类型
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 将创建一个索引器
1type MappedTypeFromKeys<Keys: string> = {[key in Keys]: number};2type MappedFooAndBarWithIndexer = MappedTypeFromKeys<'foo' | 'bar' | string>;3// = {foo: number, bar: number, [string]: number}
分布式映射类型
当映射类型使用内联 keyof
或由 $Keys
绑定的类型参数时,Flow 将在对象类型的联合上分布映射类型。
例如
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
上分布
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
属性修饰符
您还可以在映射类型中添加 +
或 -
方差修饰符和可选性修饰符 ?
1type O = {foo: number, bar: string}2type ReadOnlyPartialO = {+[key in keyof O]?: O[key]}; // = {+foo?: number, +bar?: string};
当没有提供方差或可选性修饰符并且映射类型是可分布的时,方差和可选性由输入对象确定
1type O = {+foo: number, bar?: string};2type Mapped = {[key in keyof O]: O[key]}; // = {+foo: number, bar?: string}
否则,当没有属性修饰符时,属性是读写且必需的
1type Union = 'foo' | 'bar' | 'baz';2type MappedType = {[key in Union]: number};3// = {foo: number, bar: number, baz: number};
注意:Flow 尚未支持删除方差或可选性修饰符。
采用
要使用映射类型,您需要升级您的基础设施,使其支持语法
flow
和flow-parser
:0.210.0。在 v0.210.0 到 v0.211.1 之间,您需要在您的 .flowconfig 中显式启用它,在[options]
标题下,添加mapped_type=true
。更漂亮
: 3babel
与babel-plugin-syntax-hermes-parser
。有关设置说明,请参阅我们的 Babel 指南。eslint
与hermes-eslint
。有关设置说明,请参阅我们的 ESLint 指南。