条件类型的打字稿枚举类型检查?

Typescript enum type check for conditional types?

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

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

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 采用枚举值数组或枚举键,但 return 仅采用枚举值。

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

我认为 "identify an enum" 现在不可能。即使可以,您也无法以编程方式从 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 keyed off a specific enum value), and of course, the whole deep-whatever Array trickery to avoid the dreaded "circular reference" error message mentioned here:

,则棘手的位是提取枚举的子集

Similar to union and intersection types, conditional types are not permitted to reference themselves recursively (however, indirect references through interface types or object literal types are allowed)

我们来测试一下:

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"

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