给定一些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};
}
这是一个反应挂钩,但这并不重要,因为编译它所需的只是一个哑元
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