TS as const 类型提示问题

334 天前
 jerrry
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'?

1143 次点击
所在节点    程序员
10 条回复
lisongeee
334 天前
```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'];
};
```
ChanKc
334 天前
paledream
334 天前
```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 差不多
jerrry
334 天前
@lisongeee @ChanKc 非常感谢,问题解决了,看来 TS 的类型还要多学习才是!
IvanLi127
334 天前
我也来个,和楼上思路也是一样的,但是我觉得优雅点 哈哈:

```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>);
```
gogogo1203
334 天前
我是真的讨要 keyof typeof OrderStatus. 难度得要死. 类似这种,我都让 gpt4 写,能不报错就行
gogogo1203
334 天前
const OrderStatusEnum = ['AWAITING_PAYMENT', 'AWAITING_DELIVER'] as const
(typeof OrderStatusEnum)[number] gpt4 推荐的方法. ts 一般用一些模板,需要用的时候再改改就好。 太复杂的 type inference 太难度了, 根本就是本末倒置. 不如直接 @ts-ignore
jerrry
334 天前
@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',是不是哪里写错了?
otakustay
334 天前
主要问题就是,Object.keys 它没泛型,然后你 reduce 运算后的类型和初始类型({})也是不一样的,TS 追踪不到 reduce 内部的 assignment 对类型的改变,所以你只能自己强转了
jerrry
334 天前
@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'] })
}
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/944128

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX