如何输入带枚举的函数

maa*_*nus 5 enums typescript typescript-generics

鉴于一些enum MyEnum {ONE, TWO},我想编写一个名为 like

useMyFun(MyEnum, MyEnum.ONE);
Run Code Online (Sandbox Code Playgroud)

我没有正确输入它。现在我有如下内容

type StringKeyOf<T> = Extract<keyof T, string>;
type EnumNumber<E> = Record<StringKeyOf<E>, number>;
function useMyFun<E extends EnumNumber<E>, V extends number=number> (
    anEnum: E,
    initialState: number) : {value: V, setValue: (v: V) => void}
{
    const [value, setValue] = useState<V>(initialState as V);
    //.... more stuff using both arguments omitted    
    return {value, setValue};
}
Run Code Online (Sandbox Code Playgroud)

这是一个 react-hook,但这并不重要,因为编译它所需的只是一个虚拟对象

function useState<V>(initialState: V) {
    const result: [V, (v: V) => void] = [initialState, v => { }];
    return result;
}
Run Code Online (Sandbox Code Playgroud)

它可以工作(使用当前的打字稿版本),但它也允许我调用useMyFun(MyEnum, -1),这是错误的。请注意,我只关心上面的枚举,即具有默认数值、没有指定值和const修饰符的枚举。

*我还需要返回类型具有value: MyEnum而不是number.


我知道运行时值MyEnumis{0: 'ONE', 1: 'TWO', ONE: '0', TWO: '1'}这意味着上面的输入实际上是错误的。但是,这是编译第一个参数的唯一方法。处理时的第二个参数MyEnum实际上应该是0 | 1,但我无法让它工作。

我真的需要枚举对象和函数中的值。有人可以得到正确的类型吗?

eps*_*lon 0

首先我要说的是,我强烈建议不要这样做,但为了好玩,这里有一个可以实现您正在寻找的行为的技巧。该解决方案有效地将枚举的值变成不透明类型

enum _MyEnum {
  ONE,
  TWO,
}

declare const __brand: unique symbol;

type MyEnum = {
  [K in keyof typeof _MyEnum]: (typeof _MyEnum)[K] & {
    readonly [__brand]: never;
  };
};

const MyEnum: MyEnum = _MyEnum as any;

type StringKeyOf<T> = Extract<keyof T, string>;
type EnumNumber<E> = Record<StringKeyOf<E>, number>;

function useMyFun<E extends EnumNumber<E>, V extends E[keyof E]>(
  anEnum: E,
  initialState: V
): { value: V; setValue: (v: V) => void } {
  const [value, setValue] = useState<V>(initialState as V);
  //.... more stuff using both arguments omitted
  MyEnum.ONE.toFixed;
  MyEnum.ONE;
  return { value, setValue };
}

useMyFun(MyEnum, MyEnum.ONE);
useMyFun(MyEnum, -1);
Run Code Online (Sandbox Code Playgroud)