繁体   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