如何从 TypeScript 中的合并枚举中排除某些项目?
How can I exclude some items from a merged enum in TypeScript?
我定义了以下枚举:
enum myEnum {
a = 1,
b = 2
}
enum mySecondEnum {
c = 3,
d = 4
}
后来将它们合并在一起,形成一个枚举:
const mergedEnum = {...myEnum, ...mySecondEnum};
type mergedEnum = typeof mergedEnum;
如果我现在想从合并的枚举中排除一个特定的值,我会得到一个奇怪的打字稿错误,我无法理解:
/** Type '{ [x: number]: string; c: mySecondEnum.c; d: mySecondEnum.d; a: myEnum.a; b: myEnum.b; }' does not satisfy the constraint 'string | number | symbol'.
Type '{ [x: number]: string; c: mySecondEnum.c; d: mySecondEnum.d; a: myEnum.a; b: myEnum.b; }' is not assignable to type 'symbol'.(2344) **/
const mergedOmitedEnum: Record<Exclude<mergedEnum, 1>, number> = {
...
}
**/
但是,使用相同的方法,使用非合并枚举,按预期工作:
/** This does work as expected, it omits the "1" from "myEnum" */
const simpleOmitedEnum: Record<Exclude<myEnum, 1>, number> = {
"2": 1
}
如何合并多个枚举,然后从合并的结果集中省略一些值?
这是一个playground link
考虑这一行:
const mergedEnum = { ...myEnum, ...mySecondEnum }
作为反模式。 enums
是静态已知对象,您不应该对它们进行任何操作。
你应该知道枚举的编译版本比代码表示更宽。是双向数据结构。
如果你还想合并这些数据结构,你应该改用不可变对象。
const MyEnum = {
a: 1,
b: 2
} as const
const MySecondEnum = {
c: 3,
d: 4
} as const
const MergedEnum = { ...MyEnum, ...MySecondEnum };
type MergedEnum = typeof MergedEnum;
此外,请记住 TS 类型系统不允许您创建动态枚举数据结构。
如果你想对枚举类型进行一些类型操作,你可以试试这个:
enum MyEnum {
a = 1,
b = 2
}
type Enum = `${MyEnum}`
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
>
// type Result = {
// readonly a: "1";
// readonly b: "2";
// }
type Result = EnumToObj<typeof MyEnum>
如果您对双向类型感兴趣,请查看:
enum MyEnum {
a = 1,
b = 2
}
type Enum = `${MyEnum}`
type EnumType = Record<string | number, string | number>
type ToBidirectional<Obj extends EnumType> = {
[Prop in keyof Obj as Obj[Prop]]: Prop
}
type EnumToObj<Enum extends EnumType> = Pick<
{
[Prop in keyof Enum]:
(Enum[Prop] extends string | number
? `${Enum[Prop]}`
: never)
}, keyof Enum
>
type Bidirectional<T extends EnumType> = T & ToBidirectional<T>
type PseudoEnum = Bidirectional<EnumToObj<typeof MyEnum>>
// type Test = {
// readonly a: "1";
// readonly b: "2";
// readonly 1: "a";
// readonly 2: "b";
// }
type Test = {
[Prop in keyof PseudoEnum]: PseudoEnum[Prop]
}
现在很容易省略键:
type CustomType=Omit<PseudoEnum, 1>
有关使用枚举类型表示的更多信息,您可以在我的 article
中找到
创建 mergedEnum
类型的最简单方法是合并两个不同的枚举
type mergedEnum = myEnum | mySecondEnum;
通常你会想要获取 mergedEnum
常量中值的类型,typeof mergedEnum
是常量本身的类型。要正常获取所有值的类型,我们可以做 typeof mergedEnum[keyof typeof mergedEnum]
。但是因为枚举对象有从number
到string
的索引签名,合并后的对象也会有这个签名。由于原始枚举是 number
枚举,我们可以删除从 typeof mergedEnum[keyof typeof mergedEnum]
获得的联合中额外的 string
type mergedEnum = Exclude<typeof mergedEnum [keyof typeof mergedEnum ], string>;
我定义了以下枚举:
enum myEnum {
a = 1,
b = 2
}
enum mySecondEnum {
c = 3,
d = 4
}
后来将它们合并在一起,形成一个枚举:
const mergedEnum = {...myEnum, ...mySecondEnum};
type mergedEnum = typeof mergedEnum;
如果我现在想从合并的枚举中排除一个特定的值,我会得到一个奇怪的打字稿错误,我无法理解:
/** Type '{ [x: number]: string; c: mySecondEnum.c; d: mySecondEnum.d; a: myEnum.a; b: myEnum.b; }' does not satisfy the constraint 'string | number | symbol'.
Type '{ [x: number]: string; c: mySecondEnum.c; d: mySecondEnum.d; a: myEnum.a; b: myEnum.b; }' is not assignable to type 'symbol'.(2344) **/
const mergedOmitedEnum: Record<Exclude<mergedEnum, 1>, number> = {
...
}
**/
但是,使用相同的方法,使用非合并枚举,按预期工作:
/** This does work as expected, it omits the "1" from "myEnum" */
const simpleOmitedEnum: Record<Exclude<myEnum, 1>, number> = {
"2": 1
}
如何合并多个枚举,然后从合并的结果集中省略一些值?
这是一个playground link
考虑这一行:
const mergedEnum = { ...myEnum, ...mySecondEnum }
作为反模式。 enums
是静态已知对象,您不应该对它们进行任何操作。
你应该知道枚举的编译版本比代码表示更宽。是双向数据结构。
如果你还想合并这些数据结构,你应该改用不可变对象。
const MyEnum = {
a: 1,
b: 2
} as const
const MySecondEnum = {
c: 3,
d: 4
} as const
const MergedEnum = { ...MyEnum, ...MySecondEnum };
type MergedEnum = typeof MergedEnum;
此外,请记住 TS 类型系统不允许您创建动态枚举数据结构。
如果你想对枚举类型进行一些类型操作,你可以试试这个:
enum MyEnum {
a = 1,
b = 2
}
type Enum = `${MyEnum}`
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
>
// type Result = {
// readonly a: "1";
// readonly b: "2";
// }
type Result = EnumToObj<typeof MyEnum>
如果您对双向类型感兴趣,请查看:
enum MyEnum {
a = 1,
b = 2
}
type Enum = `${MyEnum}`
type EnumType = Record<string | number, string | number>
type ToBidirectional<Obj extends EnumType> = {
[Prop in keyof Obj as Obj[Prop]]: Prop
}
type EnumToObj<Enum extends EnumType> = Pick<
{
[Prop in keyof Enum]:
(Enum[Prop] extends string | number
? `${Enum[Prop]}`
: never)
}, keyof Enum
>
type Bidirectional<T extends EnumType> = T & ToBidirectional<T>
type PseudoEnum = Bidirectional<EnumToObj<typeof MyEnum>>
// type Test = {
// readonly a: "1";
// readonly b: "2";
// readonly 1: "a";
// readonly 2: "b";
// }
type Test = {
[Prop in keyof PseudoEnum]: PseudoEnum[Prop]
}
现在很容易省略键:
type CustomType=Omit<PseudoEnum, 1>
有关使用枚举类型表示的更多信息,您可以在我的 article
中找到创建 mergedEnum
类型的最简单方法是合并两个不同的枚举
type mergedEnum = myEnum | mySecondEnum;
通常你会想要获取 mergedEnum
常量中值的类型,typeof mergedEnum
是常量本身的类型。要正常获取所有值的类型,我们可以做 typeof mergedEnum[keyof typeof mergedEnum]
。但是因为枚举对象有从number
到string
的索引签名,合并后的对象也会有这个签名。由于原始枚举是 number
枚举,我们可以删除从 typeof mergedEnum[keyof typeof mergedEnum]
string
type mergedEnum = Exclude<typeof mergedEnum [keyof typeof mergedEnum ], string>;