【问题标题】:Typescript enum type check for conditional types?Typescript枚举类型检查条件类型?
【发布时间】:2018-10-31 07:09:31
【问题描述】:

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

这是我想要的,但它在语法上无效:

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 以便任何嵌套的枚举都得到这种处理 - 不必具有由请求和响应分区的单独的类型层次结构。

【问题讨论】:

  • 我认为您无法以编程方式识别enum。我得到的最接近的是type IsEnum&lt;T&gt; = T extends Record&lt;keyof T, string | number&gt; ? true : false,但无论如何你都需要EnumOrString&lt;typeof Features&gt;
  • 等等,所以你想要一些采用数据结构并递归地将 Features 更改为 Features | keyof typeof Features 的东西?
  • 好吧,any 枚举类型的成员(递归) - 但并非所有成员都会被枚举类型
  • 这个问题有两个部分,然后......一个是“识别枚举”,我认为你做不到。另一种是“用枚举值和枚举对象的键的联合递归替换枚举类型”,如果您事先知道您关心哪些枚举(例如,@ 987654331@).

标签: typescript enums mapped-types conditional-types


【解决方案1】:

我认为“识别enum”的事情现在是不可能的。即使可以,您也无法以编程方式将 Features 类型(Features 枚举的 元素)转换为 typeof Features 类型(映射 em> 从键到Features 元素)首先不知道Features。同样:例如,Features.B 类型对字符串文字 "B" 一无所知。只有typeof Features 具有类似{B: Features.B} 的属性。如果您希望类型函数从Features 转换为Features | keyof typeof Features,则需要明确提及typeof Features。所以即使你有你的梦想extends enum 符号,你仍然需要用你关心的映射列表来编写替换代码。对不起。


仅解决递归部分,以防万一,这是我如何递归处理一个类型以用枚举值和相关键的并集替换 known 枚举值:

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 锁定特定的枚举值),那么棘手的位是提取枚举的子集,当然,整个深度无论如何数组诡计以避免提到的可怕的“循环引用”错误消息here

类似于联合和交集类型,条件类型不允许递归引用自身(但是,允许通过接口类型或对象字面量类型进行间接引用)

让我们测试一下:

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"

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

【讨论】:

    猜你喜欢
    • 2019-12-30
    • 1970-01-01
    • 2013-03-20
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多