const OrderStatus = {
AWAITING_PAYMENT: {
value: 'AWAITING_PAYMENT',
label: '待支付'
},
AWAITING_DELIVER: {
value: 'AWAITING_DELIVER',
label: '待发货'
},
...
} as const
现在 OrderStatus.AWAITING_PAYMENT 是有类型提示 { value: 'AWAITING_PAYMENT', label: '待支付' } 的,我想写一个方法转换一下这个结构,变成
const OrderStatusEnum = {
AWAITING_PAYMENT: 'AWAITING_PAYMENT',
AWAITING_DELIVER: 'AWAITING_DELIVER'
} as const
转换方式是这样写的:
const OrderStatusEnum = Object.keys(OrderStatus).reduce((acc, key) => {
acc[key] = OrderStatus[key].value
return acc
}, {})
但是这样的方式 OrderStatusEnum 是没有类型提示的,怎么定义类型才能让 OrderStatusEnum.AWAITING_PAYMENT 会提示 'AWAITING_PAYMENT'?
1
lisongeee 2023-05-30 11:24:15 +08:00 1
```ts
const OrderStatusEnum = Object.keys(OrderStatus).reduce((acc, key) => { // @ts-ignore acc[key] = OrderStatus[key].value; return acc; }, {}) as { [P in keyof typeof OrderStatus]: (typeof OrderStatus)[P]['value']; }; ``` |
2
ChanKc 2023-05-30 11:25:15 +08:00 1
|
3
paledream 2023-05-30 11:34:19 +08:00 1
```ts
const OrderStatus = { AWAITING_PAYMENT: { value: 'AWAITING_PAYMENT', label: '待支付' }, AWAITING_DELIVER: { value: 'AWAITING_DELIVER', label: '待发货' } } as const type OrderStatusType = typeof OrderStatus type OrderStatusKey = keyof OrderStatusType type Enum = { [key in OrderStatusKey]: OrderStatusType[key]['value'] } const OrderStatusEnum = Object.keys(OrderStatus).reduce((acc, key) => { acc[key] = OrderStatus[key].value return acc }, {} as Enum) ``` 写完后发现和 1L 差不多 |
5
IvanLi127 2023-05-30 12:26:22 +08:00 1
我也来个,和楼上思路也是一样的,但是我觉得优雅点 哈哈:
```ts type enumKeys = typeof OrderStatus[keyof typeof OrderStatus]['value']; const keys = Object.keys(OrderStatus) as (keyof typeof OrderStatus)[]; const OrderStatusEnum = keys.reduce((acc, key) => { acc[key] = OrderStatus[key].value; return acc; }, {} as Record<enumKeys, string>); ``` |
6
gogogo1203 2023-05-30 12:33:20 +08:00
我是真的讨要 keyof typeof OrderStatus. 难度得要死. 类似这种,我都让 gpt4 写,能不报错就行
|
7
gogogo1203 2023-05-30 12:39:09 +08:00
const OrderStatusEnum = ['AWAITING_PAYMENT', 'AWAITING_DELIVER'] as const
(typeof OrderStatusEnum)[number] gpt4 推荐的方法. ts 一般用一些模板,需要用的时候再改改就好。 太复杂的 type inference 太难度了, 根本就是本末倒置. 不如直接 @ts-ignore |
8
jerrry OP @lisongeee @paledream
麻烦再问下,如果封装成一个函数的形式,类型该怎么定义? ```typescript function generateEnum<K extends string, V extends string>(keyMap: { [key in K]: { label: V; value: V }}) { return Object.keys(keyMap).reduce((acc, key) => { acc[key] = keyMap[key].value return acc }, {} as { [key in keyof typeof keyMap]: (typeof keyMap)[key]['value'] }) } const OrderStatusEnum = generateEnum(OrderStatus) ``` 这个时候如果调用 OrderStatusEnum.AWAITING_PAYMENT 类型提示并不是 'AWAITING_PAYMENT',是不是哪里写错了? |
9
otakustay 2023-05-30 13:16:44 +08:00
主要问题就是,Object.keys 它没泛型,然后你 reduce 运算后的类型和初始类型({})也是不一样的,TS 追踪不到 reduce 内部的 assignment 对类型的改变,所以你只能自己强转了
|
10
jerrry OP @lisongeee @paledream
不好意思,是我写错了,这样就对咯: ```typescript function generateEnum<T extends Record<string, { value: string; label: string }>>(keyMap: T) { return (Object.keys(keyMap) as (keyof T)[]).reduce((acc, key) => { acc[key] = keyMap[key].value return acc }, {} as { [key in keyof T]: T[key]['value'] }) } ``` |