已對應類型
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
。prettier
: 3babel
搭配babel-plugin-syntax-hermes-parser
。請參閱 我們的 Babel 指南 以取得設定說明。eslint
搭配hermes-eslint
。請參閱 我們的 ESLint 指南 以取得設定說明。