条件类型的打字稿枚举类型检查?
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"
看起来不错。希望对您有所帮助。
我有 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"
看起来不错。希望对您有所帮助。