给出一个看起来像这样的枚举:
Caused by: java.security.cert.CertPathValidatorException: signature check failed
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:135) ~[na:1.8.0_121]
at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:219) ~[na:1.8.0_121]
at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140) ~[na:1.8.0_121]
at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79) ~[na:1.8.0_121]
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:292) ~[na:1.8.0_121]
at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:347) ~[na:1.8.0_121]
... 79 common frames omitted
Caused by: java.security.InvalidKeyException: No installed provider supports this key: sun.security.rsa.RSAPublicKeyImpl
我想编写一个函数,该函数接受一组字符串文字并返回export enum UsedProduct {
Yes = 'yes',
No = 'no',
Unknown = 'unknown',
}
的实例。到目前为止,我编写了这样的函数:
UsedProduct
此实现不是很好,因为我必须重新定义枚举的可能值。如何重写此函数,而不必定义export function parseUsedProduct(usedProdStr: 'yes' | 'no' | 'unknown'): UsedProduct {
switch (usedProdStr) {
case 'yes':
return UsedProduct.Yes;
case 'no':
return UsedProduct.No;
case 'unknown':
return UsedProduct.Unknown;
default:
return unknownUsedProductValue(usedProdStr);
}
}
function unknownUsedProductValue(usedProdStr: never): UsedProduct {
throw new Error(`Unhandled UsedProduct value found ${usedProdStr}`);
}
?
答案 0 :(得分:6)
TypeScript对您而言并不容易,因此答案并非一帆风顺。
像enum
这样的UsedProduct.Yes
值在运行时只是一个字符串或数字文字(在这种情况下为字符串"yes"
),但是在编译时将其视为 subtype 。因此,UsedProduct.Yes extends "yes"
是正确的。不幸的是,给定类型UsedProduct.Yes
,没有编程方式将类型扩展为"yes"
......,或者给定类型UsedProduct
,没有编程方式将其扩展为{ {1}}。该语言缺少您需要执行的一些功能。
有 一种方法来制作功能类似于"yes" | "no" | "unknown"
的函数签名,但是它使用generics和conditional types来实现:
parseUsedProduct
基本上,它采用枚举对象类型type Not<T> = [T] extends [never] ? unknown : never
type Extractable<T, U> = Not<U extends any ? Not<T extends U ? unknown : never> : never>
declare function asEnum<E extends Record<keyof E, string | number>, K extends string | number>(
e: E, k: K & Extractable<E[keyof E], K>
): Extract<E[keyof E], K>
const yes = asEnum(UsedProduct, "yes"); // UsedProduct.yes
const no = asEnum(UsedProduct, "no"); // UsedProduct.no
const unknown = asEnum(UsedProduct, "unknown"); // UsedProduct.unknown
const yesOrNo = asEnum(UsedProduct,
Math.random()<0.5 ? "yes" : "no"); // UsedProduct.yes | UsedProduct.no
const unacceptable = asEnum(UsedProduct, "oops"); // error
和字符串或数字类型E
,并尝试提取扩展{{1 }}。如果没有K
的值扩展E
(或者如果K
是并集类型,其中其中一个不对应任何E
的值),则编译器将给出一个错误。 K
和K
的工作原理可根据要求提供。
关于功能的实现,您可能需要使用type assertion。像这样:
E
应该可以。在您的特定情况下,我们可以对Not<>
进行硬编码:
Extractable<>
希望有帮助。祝你好运!
答案 1 :(得分:0)
您可以使用ts-enum-util中的getKeyOrThrow
方法。不知道它是如何实现的,但是您可以查看它here。
Here's a stackblitz是为了演示您的情况。
答案 2 :(得分:0)
使用Typescript 4.1,可以用更简单的方式完成
type UnionToEnum<E extends string, U extends `${E}`> = {
[enumValue in E as `${enumValue & string}`]: enumValue
}[U]
enum UsedProduct {
Yes = 'yes',
No = 'no',
Unknown = 'unknown',
}
function parseUsedProduct<K extends `${UsedProduct}`>(k: K): UnionToEnum<UsedProduct, K> {
if (Object.values(UsedProduct).indexOf(k as UsedProduct) < 0)
throw new Error("Expected one of " + Object.values(UsedProduct).join(", "));
return k as UsedProduct as UnionToEnum<UsedProduct, K>;
}
// x is of type UsedProduct.Yes
let x = parseUsedProduct('yes');
// error
let c = parseUsedProduct('noo');
这里的键是`${UsedProduct}`
,它删除枚举值的“枚举”并将其转换为字符串文字。
注意:仅适用于字符串枚举值,不适用于数字枚举值。