如何输入接受枚举的函数函数

2023-09-03 13:32:00 作者:薇糖~

给定一些enum MyEnum {ONE, TWO},我想编写一个名为Like的函数

useMyFun(MyEnum, MyEnum.ONE);

我打错了。现在我有如下内容

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};
}
excel if 函数 大于 等于 小于 怎么输入

这是一个反应挂钩,但这并不重要,因为编译它所需的只是一个哑元

function useState<V>(initialState: V) {
    const result: [V, (v: V) => void] = [initialState, v => { }];
    return result;
}
它可以工作(使用当前的打字版本),但它也允许我调用useMyFun(MyEnum, -1),这是错误的。请注意,我只关心上面这样的枚举,即具有默认数值、没有指定值和没有const修饰符的枚举。

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

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

我确实需要函数中的枚举对象和值。有没有人能把类型搞对?

推荐答案

相关问题here

还有一种方法可以确定初始值是否有效。

如您所知,TS可能将enum视为number或对象或typeof enum。以类似的方式处理classes

我们需要一些如何获取enum的数字键。

让我们尝试迭代enum键:

enum MyEnum {
    ONE,
    TWO
}

type Enumerate<Enum extends number | string> = keyof {
    [Prop in Enum]: Prop
}

// non generic version 
type Keys = keyof typeof MyEnum
type Enumerate2 = keyof {
    [Prop in Keys]: Prop
}


type Result = Enumerate<MyEnum> // MyEnum, not good

它不起作用,因为TS足够聪明,可以知道我们正在迭代枚举键。因此,我们得到的是MyEnum而不是0 | 1

我们可以将Prop键换成字符串以作弊打字。

enum MyEnum {
    ONE,
    TWO
}

type Enumerate<Enum extends number | string> = keyof {
    [Prop in `${Enum}`]: Prop
}

type Result = Enumerate<MyEnum> // "0" | "1"

现在好多了。但这仍然不是我们想要的。在当前版本的TypeScrip中,无法以通用方式从字符串中提取数字。

但在比较过程中,我们总是可以将字符串与数字进行比较,这些数字被包装在字符串中。 我的意思是:"0" extends ${number}?...` 以上代码完全有效。

enum MyEnum {
    ONE,
    TWO
}

type Enumerate<Enum extends number | string> = keyof {
    [Prop in `${Enum}`]: Prop
}

type Result = Enumerate<MyEnum> // "0" | "1"


type Values<T> = T[keyof T]

type IsKeyValid<InitialValue extends number, Enum extends Record<string | number, string | number>> =
    `${InitialValue}` extends Enumerate<Values<Enum>> ? InitialValue : never

function useMyFun<
    Enum extends Record<string | number, string | number>,
    InitialValue extends number,
    >(anEnum: Enum, initialState: IsKeyValid<InitialValue, Enum>) { }

useMyFun(MyEnum, MyEnum.ONE) // ok
useMyFun(MyEnum, 0) // ok

useMyFun(MyEnum, -1) // error
useMyFun(MyEnum, NaN) // error

Playground

Enum-是推断的枚举类型

InitialValue-是第二个参数的推断类型。

IsKeyValid-是一种实用程序类型,用于检查包装成字符串的InitialValue是否等于允许的枚举键。如果等于,则返回InitialValue,否则返回never

P.S.与Reaction组件道具相关question