Typescript:带有枚举的泛型函数

mic*_*elT 8 typescript typescript-generics

我使用几个枚举作为全局参数。

enum color {
    'red' = 'red',
    'green' = 'green',
    'blue' = 'blue',
};
enum coverage {
    'none' = 'none',
    'text' = 'text',
    'background' = 'background',
};
Run Code Online (Sandbox Code Playgroud)

我将所有枚举合并为一个类型myEnums

type myEnums = color | coverage;
Run Code Online (Sandbox Code Playgroud)

现在我想检查并访问枚举的值。例如:

// Returns undefined if the argument value is not a color.
function getColor(value: string): color | undefined{
    if(value in color) return value as color;
    return undefined;
}
Run Code Online (Sandbox Code Playgroud)

因为有多个枚举,所以我想创建一个通用函数来访问所有枚举。我尝试了以下方法:

function getParam<T extends myEnums>(value: string): T | undefined {
    if(value in T) return value as T;
    return undefined;
}

getParam<color>('red', color);        // => should return 'red'
getParam<coverage>('test', coverage); // => should return undefined
Run Code Online (Sandbox Code Playgroud)

但 Typescript 编译器说: “T”仅指类型,但在这里被用作值。

list: T因此,我向该函数添加了一个参数,但随后 Typescript 假定该参数list具有类型string(而不是object)。 “in”表达式的右侧不能是原语。

function getParam<T extends allEnums>(value: string, list: T): T | undefined {
    if(value in list) return value as T;
    return undefined;
}
Run Code Online (Sandbox Code Playgroud)

那么如何使用T枚举来调用通用函数呢?

cap*_*ian 1

enum是 TypeScript 中的一种特殊数据结构。

如果你想对泛型进行限制,你需要使用typeof Enum它。

在你的例子中,你期望typeof color | typeof coverage而不是color|coverage

因为最后一个是值的联合,无论第一个是枚举的联合。

考虑这个例子:

enum color {
    'red' = 'red',
    'green' = 'green',
    'blue' = 'blue',
};
enum coverage {
    'none' = 'none',
    'text' = 'text',
    'background' = 'background',
};

type myEnums = color | coverage;

const hasProperty = <Obj, Prop extends PropertyKey>(obj: Obj, prop: Prop)
    : obj is Obj & Record<Prop, unknown> =>
    Object.prototype.hasOwnProperty.call(obj, prop);



function getParam<Keys extends PropertyKey, Value, E extends Record<Keys, Value>, Key extends keyof E>(enm: E, key: Key): E[Key]
function getParam<Keys extends PropertyKey, Value, E extends Record<Keys, Value>, Key extends PropertyKey>(enm: E, key: Key): Value | undefined
function getParam<E extends typeof color | typeof coverage, Key extends keyof E>(enm: E, key: Key): E[Key]
function getParam<E extends typeof color | typeof coverage, Key extends string>(enm: E, key: Key): undefined | E
function getParam<E extends typeof color | typeof coverage | Record<string, unknown>, Key extends keyof E>(enm: E, key: Key): E[Key] | undefined {
    return hasProperty(enm, key) ? enm[key] : undefined
}

const y = getParam(color, 'red');        // => color.red
const x = getParam(coverage, 'undefined'); // => undefined
const x2 = getParam({}, 'undefined'); // => unknown

const higherOrder = (key: string) => getParam(color, key)

const z = higherOrder('red') // typeof color | undefined
Run Code Online (Sandbox Code Playgroud)

操场

请记住,我不确定您想要如何处理高阶函数,因此我在上一个示例中仅返回了enum和的并集undefined

至于这一行if(value in T)T是一种类型,您不能将其视为运行时值。