组合枚举值并检查该枚举中是否有另一个值
Combining enum values and checking if another value is in that enum
考虑以下代码:
enum myEnum {
a = 1,
b = 2
}
enum mySecondEnum {
c = 3,
d = 4
}
enum myThirdEnum {
e = 5,
f = 6
}
/** This is an array, that should contain numbers from 1 to 4 - instead, it also contains the string keys of the enums - is there a way to limit this array to only */
const enumValuesArray = [...Object.values(myEnum), ...Object.values(mySecondEnum)];
console.log(enumValuesArray);
/** Here, b can be a number from 1 to 6 */
const b: myEnum | mySecondEnum | myThirdEnum = 5;
/** Why is typescript complaining here? I understand, that b CAN be 5 or 6 (as it is), but that is exactly the thing I want to check */
if (enumValuesArray.includes(b)) {
console.log("Included");
} else console.log("Not included");
虽然此代码按预期编译和运行,但当我尝试检查输出数组是否包含“b”的值时,TypeScript 会报错。我收到的错误消息如下:
Argument of type 'myEnum | mySecondEnum | myThirdEnum' is not assignable to parameter of type 'string | myEnum | mySecondEnum'.
Type 'myThirdEnum.e' is not assignable to type 'string | myEnum | mySecondEnum'.(2345)
我该如何解决这个错误?
作为第二个注意事项,是否有可能以某种方式仅检索枚举值数组,而不是枚举值和属性?
首先,值得使用不可变对象而不是数字枚举。
参见示例:
const myEnum = {
a: 1,
b: 2
} as const
const mySecondEnum = {
c: 3,
d: 4
} as const
const myThirdEnum = {
e: 5,
f: 6
} as const
现在,enumValuesArray
有一个预期的类型:
// (1 | 2 | 3 | 4)[]
const enumValuesArray = [...Object.values(myEnum), ...Object.values(mySecondEnum)];
至于Array.prototype.includes
的错误。这是已知问题。 TS 只允许您使用 enumValuesArray
.
中存在的数字
有一个通用但有点冗长的解决方法。
优点:不需要类型断言
缺点:冗长且需要你咖喱。
完整示例:
const myEnum = {
a: 1,
b: 2
} as const
const mySecondEnum = {
c: 3,
d: 4
} as const
const myThirdEnum = {
e: 5,
f: 6
} as const
type Values<T> = T[keyof T]
type Primitives =
| string
| number
| bigint
| boolean
| symbol
| null
| undefined
type InferPrimitive<T, P> = P extends any ? T extends P ? P : never : never;
type Inference<T> = InferPrimitive<T, Primitives>
const withTuple = <
List extends Primitives[]
>(list: readonly [...List]) =>
(prop: Inference<List[number]>):
prop is Inference<List[number]> & List[number] =>
list.includes(prop)
// (1 | 2 | 3 | 4)[]
const enumValuesArray = [...Object.values(myEnum), ...Object.values(mySecondEnum)];
const includes = withTuple(enumValuesArray);
type DistributeValues<T> = T extends any ? Values<T> : never
// 1 | 2 | 3 | 4 | 5 | 6
type AllowedValues = DistributeValues<typeof myEnum | typeof mySecondEnum | typeof myThirdEnum>
/** Here, b can be a number from 1 to 6 */
const b: AllowedValues = 5; // ok
/** Why is typescript complaining here? I understand, that b CAN be 5 or 6 (as it is), but that is exactly the thing I want to check */
if (includes(b)) {
console.log("Included");
} else console.log("Not included");
includes('a') // expected error
有关 includes
的更多说明,您可以在我的 article
中找到
InferPrimitive
- 将文字类型缩小为更宽的类型。例如 InferPrimitive<42>
将 return number
.
考虑以下代码:
enum myEnum {
a = 1,
b = 2
}
enum mySecondEnum {
c = 3,
d = 4
}
enum myThirdEnum {
e = 5,
f = 6
}
/** This is an array, that should contain numbers from 1 to 4 - instead, it also contains the string keys of the enums - is there a way to limit this array to only */
const enumValuesArray = [...Object.values(myEnum), ...Object.values(mySecondEnum)];
console.log(enumValuesArray);
/** Here, b can be a number from 1 to 6 */
const b: myEnum | mySecondEnum | myThirdEnum = 5;
/** Why is typescript complaining here? I understand, that b CAN be 5 or 6 (as it is), but that is exactly the thing I want to check */
if (enumValuesArray.includes(b)) {
console.log("Included");
} else console.log("Not included");
虽然此代码按预期编译和运行,但当我尝试检查输出数组是否包含“b”的值时,TypeScript 会报错。我收到的错误消息如下:
Argument of type 'myEnum | mySecondEnum | myThirdEnum' is not assignable to parameter of type 'string | myEnum | mySecondEnum'. Type 'myThirdEnum.e' is not assignable to type 'string | myEnum | mySecondEnum'.(2345)
我该如何解决这个错误?
作为第二个注意事项,是否有可能以某种方式仅检索枚举值数组,而不是枚举值和属性?
首先,值得使用不可变对象而不是数字枚举。 参见示例:
const myEnum = {
a: 1,
b: 2
} as const
const mySecondEnum = {
c: 3,
d: 4
} as const
const myThirdEnum = {
e: 5,
f: 6
} as const
现在,enumValuesArray
有一个预期的类型:
// (1 | 2 | 3 | 4)[]
const enumValuesArray = [...Object.values(myEnum), ...Object.values(mySecondEnum)];
至于Array.prototype.includes
的错误。这是已知问题。 TS 只允许您使用 enumValuesArray
.
有一个通用但有点冗长的解决方法。 优点:不需要类型断言 缺点:冗长且需要你咖喱。
完整示例:
const myEnum = {
a: 1,
b: 2
} as const
const mySecondEnum = {
c: 3,
d: 4
} as const
const myThirdEnum = {
e: 5,
f: 6
} as const
type Values<T> = T[keyof T]
type Primitives =
| string
| number
| bigint
| boolean
| symbol
| null
| undefined
type InferPrimitive<T, P> = P extends any ? T extends P ? P : never : never;
type Inference<T> = InferPrimitive<T, Primitives>
const withTuple = <
List extends Primitives[]
>(list: readonly [...List]) =>
(prop: Inference<List[number]>):
prop is Inference<List[number]> & List[number] =>
list.includes(prop)
// (1 | 2 | 3 | 4)[]
const enumValuesArray = [...Object.values(myEnum), ...Object.values(mySecondEnum)];
const includes = withTuple(enumValuesArray);
type DistributeValues<T> = T extends any ? Values<T> : never
// 1 | 2 | 3 | 4 | 5 | 6
type AllowedValues = DistributeValues<typeof myEnum | typeof mySecondEnum | typeof myThirdEnum>
/** Here, b can be a number from 1 to 6 */
const b: AllowedValues = 5; // ok
/** Why is typescript complaining here? I understand, that b CAN be 5 or 6 (as it is), but that is exactly the thing I want to check */
if (includes(b)) {
console.log("Included");
} else console.log("Not included");
includes('a') // expected error
有关 includes
的更多说明,您可以在我的 article
InferPrimitive
- 将文字类型缩小为更宽的类型。例如 InferPrimitive<42>
将 return number
.