我想创建一个泛型类型,以检查枚举中的以下内容:
因此,在这种情况下,以下枚举将被视为“正确”:
enum correct1 {
bar = 'bar',
baz = 'baz',
}
enum correct2 {
quux = 'quux',
}
但以下内容不会:
enum wrongFoo {
bar = 'bar',
baz = 'WRONG',
}
enum wrongFoo2 {
bar = 1
}
实现此目标的正确语法是什么?
答案 0 :(得分:1)
听起来像您可以使用我们编写的实用程序。它本身并不会创建枚举,但是会创建一个类型安全的对象,其中键的名称为其值,并使用keyof typeof
来保护字符串类型。
这是在字符串枚举存在之前创建的,这就是为什么称为枚举,但实际上不是枚举的原因。它只是一个对象,但您可以使用它代替对字符串进行硬编码。
/**
* This creates a fake string enum like object. Use like so:
* const Ab = strEnum(['a', 'b']);
* type AbKeys = keyof typeof Ab;
* @param keys keys in the enum
* @returns enum object
*/
export function createStringEnum<T extends string>(keys: T[]): {[K in T]: K} {
return keys.reduce((res, key) => {
res[key] = key;
return res;
}, Object.create(null));
}
const Ab = createStringEnum(['a', 'b']);
type AbKeys = keyof typeof Ab;
const Bc = createStringEnum(['b', 'c']);
type BcKeys = keyof typeof Ab;
console.log(Bc.blah) // Compilation error blah property does not exist
// Error invalid string
const b: AbKeys = "e";
// An enum throws an error, but this isn't really an enum
// Main drawback of this approach
const a: AbKeys = Bc.b;
即使它不符合您的需求,这也可能对不需要使用枚举的其他人很有帮助。
答案 1 :(得分:1)
如果您可以接受手动编译时检查(意味着必须在enum
定义之后手动编写内容),则可以执行以下操作:
type EnsureCorrectEnum<T extends { [K in Exclude<keyof T, number>]: K }> = true;
然后让编译器评估EnsureCorrectEnum<typeof YourEnumObjectHere>
。如果可以编译,那就太好了。如果没有,那就有问题:
type Correct1Okay = EnsureCorrectEnum<typeof correct1>; // okay
type Correct2Okay = EnsureCorrectEnum<typeof correct2>; // okay
type WrongFooBad = EnsureCorrectEnum<typeof wrongFoo>; // error!
// ┌─────────────────────────────> ~~~~~~~~~~~~~~~
// Types of property 'baz' are incompatible.
type WrongFoo2Bad = EnsureCorrectEnum<typeof wrongFoo2>; // error!
// ┌──────────────────────────────> ~~~~~~~~~~~~~~~~
// Types of property 'bar' are incompatible.
错误也具有描述性。
好的,希望能有所帮助;祝你好运!
答案 2 :(得分:0)
Typescript中的枚举是对象,因此您可以使用Object.keys
函数来获取该枚举中的所有键并检查它们是否等于它们的值。由于Object.keys
函数返回的所有键都是字符串,因此值也必须是字符串。
enum correct1 {
bar = 'bar',
baz = 'baz',
}
enum correct2 {
quux = 'quux',
}
enum wrongFoo {
bar = 'bar',
baz = 'WRONG',
}
enum wrongFoo2 {
bar = 1
}
function isEnumValid<T extends {}>(validatedEnum: T) : boolean {
return Object.keys(validatedEnum).every(k => k === validatedEnum[k]);
}
console.log(isEnumValid(correct1)); // true
console.log(isEnumValid(correct2)); // true
console.log(isEnumValid(wrongFoo)); // false
console.log(isEnumValid(wrongFoo2)); // false
答案 3 :(得分:0)
避免每次检查都声明新类型的另一种方式:
const keyValuesMatch = <T>(kv: { [K in keyof T]: K }) => {};
enum correct {
bar = 'bar',
baz = 'baz',
}
enum incorrect {
bar = 'bar',
baz = 'wrong',
}
keyValuesMatch(correct);
keyValuesMatch(incorrect); // Type 'incorrect.baz' is not assignable to type '"baz"'.