typescript枚举类型检查条件类型?

时间:2018-05-21 15:28:06

标签: typescript enums mapped-types conditional-types

我有宁静的服务,接受枚举值作为数字或字符串,但总是只返回数字。有没有办法输入它们?

这是我想要的东西,但它在语法上并不合适:

enum Features {
  "A" = 1,
  "B" = 2,
  "C" = 2
}

type EnumOrString<T> = T extends enum
  ? T | keyof T
  : T

declare function getData(featureFilter: EnumOrString<Features>[]): Features[]

getData获取枚举值或枚举键的数组,但只返回枚举值。

I also would want to extend this to mapped types like DeepPartial这样任何嵌套的枚举都可以得到这种处理 - 而不必具有由请求和响应分区的单独的类型层次结构。

1 个答案:

答案 0 :(得分:2)

我不认为&#34;识别enum&#34;现在有可能。即使可以,您也可以通过编程方式将Features类型(Features枚举的元素)转换为typeof Features类型(从密钥到Features元素的映射)首先不知道Features。再次:类型Features.B例如,对字符串文字"B"一无所知。只有typeof Features具有{B: Features.B}之类的属性。如果您希望类型函数从Features转换为Features | keyof typeof Features,则需要明确提及typeof Features。因此,即使您拥有梦想的extends enum符号,您仍然需要使用您关注的映射列表编写替换代码。遗憾。

仅解决递归部分,如果重要,这里是我如何递归处理类型以用枚举值的并集替换已知的枚举值和相关的密钥:

enum Features {
  "A" = 1,
  "B" = 2,
  "C" = 2
}
type ValueOf<T> = T[keyof T]
type FeatureKey<T extends Features> =
  Extract<ValueOf<{
    [K in keyof typeof Features]: [K, typeof Features[K]]
  }>, [any, T]>[0]

type DeepFeaturesOrKey<T> =
  T extends Features ? (T | FeatureKey<T>) :
  T extends Array<infer L> ? DeepFeaturesOrKeyArray<L> :
  T extends object ? { [K in keyof T]: DeepFeaturesOrKey<T[K]> } : T

interface DeepFeaturesOrKeyArray<L> extends Array<DeepFeaturesOrKey<L>> { }

如果您没有指定整个内容(例如,您使用discriminated union键入特定的枚举值),那么棘手的部分就是提取枚举的子集,当然,整个深度 - 无论数组的诡计,以避免可怕的&#34;循环引用&#34;提到错误消息here

  

与union和intersection类型类似,不允许条件类型以递归方式引用它们(但是,允许通过接口类型或对象文字类型进行间接引用)

让我们测试一下:

interface Foo {
  bar: string,
  baz: Features,
  qux: {
    a: Features[],
    b: boolean
  },
  quux: Features.A,
  quuux: Features.B  
}

type DeepFeaturesOrKeyFoo = DeepFeaturesOrKey<Foo>
declare const deepFeaturesOrKeyFoo: DeepFeaturesOrKeyFoo
deepFeaturesOrKeyFoo.bar; // string
deepFeaturesOrKeyFoo.baz; // Features | "A" | "B" | "C"
deepFeaturesOrKeyFoo.qux.a[1];  // Features | "A" | "B" | "C"
deepFeaturesOrKeyFoo.qux.b; // boolean
deepFeaturesOrKeyFoo.quux; // Features.A | "A"
deepFeaturesOrKeyFoo.quuux; // Features.B | "B" | "C" 
// note that the compiler considers Features.B and Features.C to be the
// same value, so this becomes Features.B | "B" | "C"

看起来不错。希望有所帮助。