我收到一个数字类型= 3,必须检查它是否存在于这个enum:
export const MESSAGE_TYPE = {
INFO: 1,
SUCCESS: 2,
WARNING: 3,
ERROR: 4,
};
我发现最好的方法是将所有Enum值作为一个数组,并在其上使用indexOf。但结果代码不是很容易读懂:
if( -1 < _.values( MESSAGE_TYPE ).indexOf( _.toInteger( type ) ) ) {
// do stuff ...
}
有更简单的方法吗?
如果你在那里找不到如何检查联合包含的具体值,有解决方案:
// source enum type
export const EMessagaType = {
Info,
Success,
Warning,
Error,
};
//check helper
const isUnionHasValue = <T extends number>(union: T, value: T) =>
(union & value) === value;
//tests
console.log(
isUnionHasValue(EMessagaType.Info | EMessagaType.Success),
EMessagaType.Success);
//output: true
console.log(
isUnionHasValue(EMessagaType.Info | EMessagaType.Success),
EMessagaType.Error);
//output: false
export enum UserLevel {
Staff = 0,
Leader,
Manager,
}
export enum Gender {
None = "none",
Male = "male",
Female = "female",
}
log中的差异结果:
log(Object.keys(Gender))
=>
[ 'None', 'Male', 'Female' ]
log(Object.keys(UserLevel))
=>
[ '0', '1', '2', 'Staff', 'Leader', 'Manager' ]
解决方案,我们需要删除键作为一个数字。
export class Util {
static existValueInEnum(type: any, value: any): boolean {
return Object.keys(type).filter(k => isNaN(Number(k))).filter(k => type[k] === value).length > 0;
}
}
使用
// For string value
if (!Util.existValueInEnum(Gender, "XYZ")) {
//todo
}
//For number value, remember cast to Number using Number(val)
if (!Util.existValueInEnum(UserLevel, 0)) {
//todo
}
对于任何来这里验证字符串是否是enum值之一并对其进行类型转换的人来说,我写了这个函数,它返回正确的类型,如果字符串不在enum中则返回undefined。
function keepIfInEnum<T>(
value: string,
enumObject: { [key: string]: T }
) {
if (Object.values(enumObject).includes((value as unknown) as T)) {
return (value as unknown) as T;
} else {
return undefined;
}
}
举个例子:
enum StringEnum {
value1 = 'FirstValue',
value2 = 'SecondValue',
}
keepIfInEnum<StringEnum>('FirstValue', StringEnum) // 'FirstValue'
keepIfInEnum<StringEnum>('OtherValue', StringEnum) // undefined
下面的函数返回另一个函数,该函数作为输入enum的类型谓词(假设它是字符串样式的enum)。
function constructEnumPredicate<RuntimeT extends string, EnumClass extends {[key: string]: RuntimeT}>(enumClass: EnumClass): (maybeEnum: string) => maybeEnum is EnumClass[keyof EnumClass] {
const reverseMapping: {[key: string]: boolean} = {};
for (const enumVal in enumClass) {
const enumStr = enumClass[enumVal];
reverseMapping[enumStr] = true;
}
function result(maybeEnum: any): maybeEnum is EnumClass[keyof EnumClass] {
return !!reverseMapping[maybeEnum];
}
return result;
}
它可以在TypeScript 4.2.4中工作,但我还没有测试早期版本。
主要有趣的部分是EnumClass[keyof EnumClass]返回类型。当这样的类型是TypeScript中的enum时,它会返回enum的原始类型,其中EnumClass是运行时enum类的类型。
对于如何使用这个结构的例子,假设我们有以下枚举:
enum Direction {
Left = "<-",
Right = "->"
}
Direction既是一种类型,也是一个运行时对象。我们可以为Direction生成一个类型谓词,并像这样使用它:
const isDirection = constructEnumPredicate(Direction);
function coerceDirection(maybeDir: string): Direction {
// Since we make a type predicate rather than just a normal predicate,
// no explicit type casting is necessary!
return isDirection(maybeDir) ? maybeDir : Direction.Left;
}
enum ServicePlatform {
UPLAY = "uplay",
PSN = "psn",
XBL = "xbl"
}
就变成:
{ UPLAY: 'uplay', PSN: 'psn', XBL: 'xbl' }
so
ServicePlatform.UPLAY in ServicePlatform // false
解决方案:
ServicePlatform.UPLAY.toUpperCase() in ServicePlatform // true