Nik*_*ili 1 javascript typescript
我有一个这样的枚举:
enum Test {
'type1',
'type2',
'type3',
'type4',
'type5'
}
function getType(num: number) {
}
Run Code Online (Sandbox Code Playgroud)
我想要的是如果num = 1
,返回type1
,如果num = 2
,返回type2
,如果num >= 5
,返回type5
。
我怎样才能做到这一点getType
?
枚举的运行时表示是双向对象。
const Test = {
0: "type1",
1: "type2",
2: "type3",
3: "type4",
4: "type5",
type1: 0,
type2: 1,
type3: 2,
type4: 3,
type5: 4,
}
Run Code Online (Sandbox Code Playgroud)
请在阅读时牢记这一点。
考虑这个例子:
enum MyEnum {
ONE, // 0
TWO // 1
}
// This utility type reverses object.
// All keys become values an all values become keys
type ReverseObj<T extends Record<string, string | number>> = {
[Prop in keyof T as T[Prop]]: Prop
}
{
type _ = ReverseObj<{ age: 42 }> // { 42: "age" }
}
// Type representation of runtime enum value
// Please keep in mind that enum runtime value is bidirectional
// this is why I have used ReverseObject
type EnumToObj = Pick<
{
[Prop in keyof typeof MyEnum]: `${typeof MyEnum[Prop]}`
}, keyof typeof MyEnum
>
type IsKeyValid<
InitialValue extends number,
> =
`${InitialValue}` extends keyof ReverseObj<EnumToObj>
? InitialValue
: never
{
type _ = IsKeyValid<1> // 1
type __ = IsKeyValid<2> // never
}
function handleEnum<
Index extends number,
>(index: IsKeyValid<Index>): `${Index}` extends keyof ReverseObj<EnumToObj> ? ReverseObj<EnumToObj>[`${Index}`] : never
function handleEnum<
Index extends number,
>(index: IsKeyValid<Index>) {
return MyEnum[index]
}
handleEnum(0) // "ONE"
handleEnum(1) // "TWO"
handleEnum(2) // expected error
handleEnum('ONE') // expected error
handleEnum(0.1) // expected error
handleEnum(NaN) // expected error
handleEnum(Infinity) // expected error
Run Code Online (Sandbox Code Playgroud)
您会在评论中找到一些解释。目标是让非法国家无法代表。
IsKeyValid
- 确保不允许您提供枚举中不存在的密钥。例如,您不允许打电话,handleEnum(10)
因为我们只有两个键,因此允许的键是0 | 1
。至于返回值,我是从reverse object中获取的ReverseObj
。
您应该注意一些事情:
typeof MyEnum
和MyEnum
不相等。as
有关使用in 的更多说明[Prop in keyof T as T[Prop]]: Prop
可以在这里找到const TUPLE = ['one', 'two', 'three'] as const;
type Tuple = typeof TUPLE
type AllowedIndex<Index extends number> = `${Index}` extends Exclude<keyof Tuple, keyof ReadonlyArray<any>> ? Index : never
const getter = <Index extends number>(index: AllowedIndex<Index>) =>
TUPLE[index]
getter(1) // ok, returns "two"
getter(23) // expected error
Run Code Online (Sandbox Code Playgroud)
const FakeEnum = {
a: 0,
b: 1
} as const
Run Code Online (Sandbox Code Playgroud)
使用FakeEnum
对象很容易。因为你可以轻松地、无需任何技巧地获取对象的键和适当的值。
恕我直言,我认为这不是enum
在这种情况下使用的最佳选择
PS如果您不喜欢枚举中的从零开始的索引,您可以设置初始值:
enum MyEnum {
ONE = 1, // 1
TWO // 2
}
Run Code Online (Sandbox Code Playgroud)
更新
上述方法有其自身的缺点。您可能已经注意到,所有实用程序类型都与MyEnum
. 它们不是通用的。如果您对可以传递任何枚举的通用解决方案感兴趣,请考虑以下示例:
enum MyEnum {
ONE, // 0
TWO // 1
}
/**
* Obtains a union of all dictionary values
*/
type Values<T> = T[keyof T]
/**
* Represents any enum type
*/
type EnumType = Record<string | number, string | number>
type EnumToObj<Enum extends EnumType> = Pick<
{
[Prop in keyof Enum]:
(Enum[Prop] extends string | number
? `${Enum[Prop]}`
: never)
}, keyof Enum
>
{
// {
// readonly ONE: "0";
// readonly TWO: "1";
// }
type Test = EnumToObj<typeof MyEnum>
}
type GetEnumValue<
Enum extends EnumType,
Index extends number,
Obj extends EnumToObj<Enum> = EnumToObj<Enum>
> =
{
[Prop in keyof Obj]:
(`${Index}` extends Obj[Prop]
? Prop
: never)
}[keyof Enum];
{
type Test = GetEnumValue<typeof MyEnum, 1> // TWO
}
type IsNever<T> = [T] extends [never] ? true : false
type IsKeyValid<
Index extends number,
Enum extends EnumType
> =
IsNever<GetEnumValue<Enum, Index>> extends true
? never
: Index
{
type _ = IsKeyValid<1, typeof MyEnum> // 1
type __ = IsKeyValid<2, typeof MyEnum> // never
}
function handleEnum<
Index extends number,
Enum extends EnumType
>(
enEnum: Enum,
index: IsKeyValid<Index, Enum>
): GetEnumValue<Enum, Index>
function handleEnum<
Index extends number,
Enum extends EnumType
>(enEnum: Enum, index: IsKeyValid<Index, Enum>) {
return enEnum[index]
}
const x = handleEnum(MyEnum, 0) // "ONE"
const y = handleEnum(MyEnum, 1) // "TWO"
handleEnum(MyEnum, 2) // expected error
handleEnum(MyEnum, 'ONE') // expected error
Run Code Online (Sandbox Code Playgroud)