簡體   English   中英

對於定義為枚舉值到字符串的映射的類型,如何使用流檢查映射對象文字是否具有每個枚舉值的鍵?

[英]For a type defined as a map of enum values to strings, how to check with flow that the map object literal has a key for every enum value?

假設我有這種類型

type Status = "draft" | "validated" | "private" | "available" | "archived";

我正在實例化將此枚舉類型映射到字符串的對象:

const statusNameMap: { [Status]: string } = {
  "draft": "Draft",
  "validated": "Validated",
  "private": "Private",
  "available": "Available",
  "archived": "Archived",
};

這工作得很好。 現在的問題是,如何在類型級別檢查對象文字必須包含Status枚舉中的所有值作為鍵?

主要動機是Status類型實際上不在我的控制范圍內,這是通過自省 GraphQL 模式生成的代碼,而對象映射用於演示目的。 如果枚舉值被添加/刪除,我希望 Flow 抱怨我的對象文字沒有正確的鍵。

目前 Flow 可以做到這一點嗎?

不 - 至少不是你想要的方式。 據我所知,這不受支持,對我來說壓力很大。

但是,您可以使用$ObjMap來獲得您想要的東西。

const MyEnumValues = Object.freeze({
  KEY_A: 'VALUE_A', 
  KEY_B: 'VALUE_B', 
  KEY_C: 'VALUE_C', 
});
const Test8: $Exact<$ObjMap<typeof MyEnumValues, () => string>> = ({
    'KEY_A': '',
    'KEY_B': '',
    //'KEY_C': '', // Errors here!
});

導致在引擎蓋下可能看起來像這樣的類型:

$Exact<$ObjMap<typeof MyEnumValues, () => string>> = {|
  KEY_A: string,
  KEY_B: string,
  KEY_C: string,
|}

好樣的如果您的鍵和值相同,那么這可能正是您想要的,但它仍然令人沮喪。

這是我運行的測試用例,以獲取一個簡單的 Enum 設置為 Value set here 我還在此處包含了代碼,以防 try flow 脫機。

/* @flow */

export const MyEnumValues = Object.freeze({
  KEY_A: 'VALUE_A', 
  KEY_B: 'VALUE_B', 
  KEY_C: 'VALUE_C', 
});

export type MyEnum = $Values<typeof MyEnumValues>;
type ExactMyEnumMap = $Exact<{| +[key: MyEnum]: string |}>;
// NOTE: Needs $Exact bc theres another bug here - only using `|` doesn't work.
//       Still doesn't map one-to-one
const Test1: ExactMyEnumMap = {
    [MyEnumValues.KEY_A]: '',
    // NOTE: Should error...
};
// Exact explicit object literal type
const Test2: ExactMyEnumMap = ({
    [MyEnumValues.KEY_A]: '',
    // NOTE: Should error...
})
// Explicit object map type.
const Test3: $ObjMap<{| a: 1, b: 2 |}, () => string> = ({
    a: '',
    b: ''
    // NOTE: WORKS -> Except that you have to "redefine" tye type again...
})
// Explicit exact map object literal type. (Ext type)
const Test4: $Exact<$ObjMap<ExactMyEnumMap, () => string>> = ({
    [MyEnumValues.KEY_A]: '',
    // NOTE: Should error...
})
// Explicit object map object literal type.
const Test5: $ObjMap<{| [MyEnum]: string |}, () => string> = ({
    // NOTE: Should error...
})
// Map function type.
const Test6 = (lookup: MyEnum)/* string - same with explicit */ => {
    switch (lookup) {
        case MyEnumValues.KEY_A:
            return '';
        case MyEnumValues.KEY_B:
            return '';
        // NOTE: Should error...
        //       Typescript reports "not all code paths return a value"
    }
}
// Explicit map type.
const Test7: Map<MyEnum, string> = new Map([
    // NOTE: Probably shouldn't error but was hoping it would.
]);
// Explicit map type (KEYS ONLY).
const Test8: $Exact<$ObjMap<typeof MyEnumValues, () => string>> = ({
    'KEY_A': '',
    'KEY_B': '',
    //'KEY_C': '', // YES!
});

您可以在這種情況下使用精確類型並使用 {| 定義類型 ... |} 看起來像

 const statusNameMap: { [Status]: string } = {|
  "draft": "Draft",
  "validated": "Validated",
  "private": "Private",
  "available": "Available",
  "archived": "Archived",
|};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM