TS4.1 ANSWER:
type UsedProductType = `${UsedProduct}`;
TS-4.1 之前的答案:
TypeScript 对您来说并不容易,所以答案不是单行的。
像UsedProduct.Yes 这样的enum 值在运行时只是一个字符串或数字文字(在本例中为字符串"yes"),但在编译时它被视为一个子类型的字符串或数字文字。所以,UsedProduct.Yes extends "yes" 是真的。不幸的是,给定类型UsedProduct.Yes,没有编程方法可以将类型扩展为"yes"...,或者,给定类型UsedProduct,没有编程方法可以将其扩展为"yes" | "no" | "unknown"。该语言缺少一些您需要执行此操作的功能。
有一种方法可以创建一个函数签名,其行为类似于parseUsedProduct,但它使用generics 和conditional types 来实现此目的:
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 和字符串或数字类型K,并尝试提取扩展K 的E 的属性值。如果没有E 的值扩展K(或者如果K 是联合类型,其中一个部分不对应于E 的任何值),编译器将给出错误。 Not<> 和 Extractable<> 的具体工作方式可应要求提供。
至于函数的实现,您可能需要使用type assertion。比如:
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> {
// runtime guard, shouldn't need it at compiler time
if (Object.values(e).indexOf(k) < 0)
throw new Error("Expected one of " + Object.values(e).join(", "));
return k as any; // assertion
}
应该可以。在您的具体情况下,我们可以硬编码UsedProduct:
type Not<T> = [T] extends [never] ? unknown : never
type Extractable<T, U> = Not<U extends any ? Not<T extends U ? unknown : never> : never>
function parseUsedProduct<K extends string | number>(
k: K & Extractable<UsedProduct, K>
): Extract<UsedProduct, K> {
if (Object.values(UsedProduct).indexOf(k) < 0)
throw new Error("Expected one of " + Object.values(UsedProduct).join(", "));
return k as any;
}
const yes = parseUsedProduct("yes"); // UsedProduct.yes
const unacceptable = parseUsedProduct("oops"); // error
希望对您有所帮助。祝你好运!