type Vegetable = "茄子" | "黄瓜" | "西红柿"
type List = {
[key in Vegetable]: {
price: number;
num: number;
};
}
const list: List = {
"茄子": {
price: 5,
num: 2
},
"西红柿": {
price: 5,
num: 2
},
"黄瓜": {
price: 5,
num: 2
},
}
Object.entries(list).map(([key, item]) => {
// 这儿的 key 不再是 Vegetable, 而是 string, 怎么能维持它的 Vegetable 类型呢?
})
1
geekdada 2019-08-27 16:46:51 +08:00
运行在 Runtime 里的还是 JS 代码,所以你在运行时拿到的类型是 string。
|
2
ochatokori 2019-08-27 16:49:26 +08:00 via Android
可能我不会 ts,用 ts 有很多这样类似的问题
实在不行就<Vegetable> |
3
Hypn0s 2019-08-27 16:51:53 +08:00
```javascript
Object.entries(list).map(([trueKey, item]) => { let key1 = <Vegetable>trueKey; let key2 = trueKey as Vegetable; }) ``` 实在没办法 |
4
azh7138m 2019-08-27 16:52:16 +08:00 1
entries 定义是
entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][]; entries(o: {}): [string, any][]; 你得自己提供一个 entries 来 hack 这个 key 的类型 |
5
azh7138m 2019-08-27 17:04:45 +08:00
目前在 ts 里面构造出一个数组长度是一个对象 key 的数量,这种操作很难做通用实现
value 类型固定的,给个 xjb 的做法的话 在代码前面写一个 interface ObjectConstructor { entries<O>(o: O): [keyof O, O[keyof O]][]; } 后面的 entries 就能拿到类型了 但是我不推荐这样子写,因为不通用 如果场景足够单一,可以补充一个 entries 的定义,如果还有别的场景,建议手动指定 key 的类型 |
6
wawaforya 2019-08-27 17:05:29 +08:00
```
Object.entries(list).map(([key, item]: [Vegetable, { price: number; num: number }]) => { // 可以给参数加个类型定义 }); ``` |
7
xiaoming1992 OP @wawaforya 没用,提示不能将 string 赋给 Vegetable
|
8
jatai 2019-08-27 17:33:05 +08:00 via Android
什么? ts 也设置类型? 前端高手不都是用 any 吗
|
9
xiaoming1992 OP |
10
xiaoming1992 OP 可能因为我菜吧 /(ㄒoㄒ)/~~
|
11
azh7138m 2019-08-27 17:43:14 +08:00
@xiaoming1992 并不,他们不是一个概念,补充一个新的签名是重载,js 里面没有这个概念
|
12
xiaoming1992 OP @azh7138m 不是说`重载`必须要将`函数定义`紧挨着`interface`写吗?还可以半中间插进来?王自如觉得很 awesome👍
|
13
azh7138m 2019-08-27 18:03:22 +08:00
|
14
optional 2019-08-27 18:19:26 +08:00
type List = {
[key in Vegetable]: { price: number; num: number; }; } 这只能保证 list[Vegetable] 的 type 是 {price,num},并不能保证所有 key 都是{price,num} 不信你试试 const list = {} as List const o = list['any'] list['xx'] = 1; 是合法的,list['any'] 的类型是 any 能保证的是 type List = { [key : Vegetable]: { price: number; num: number; }; } 但是这又是不合法的。 |
15
wawaforya 2019-08-27 18:27:08 +08:00 2
@xiaoming1992 , 我这边可以的啊,难道是版本问题?我 typescript 的版本是 3.5.3
PS: List 其实可以用 Record 来定义,Record<Vegetable, { price: number; num: number }> |
16
xiaoming1992 OP |
17
optional 2019-08-27 18:45:41 +08:00
@xiaoming1992 不会报错
|
18
zbinlin 2019-08-27 22:00:17 +08:00
entries 的签名写死了 string,你试试加上这个自动推导的签名:
declare global { interface ObjectConstructor { entries<S extends string, T>(list: { [key in S]: T }): [S, T][]; } } |
19
xiaoming1992 OP @zbinlin .如果这么搞的话,那什么 map foreach 什么的都要声明。。。
|
20
zbinlin 2019-08-28 00:12:07 +08:00
@xiaoming1992 不需要呀,为什么需要,map, foreach 这些已经能正确地推导出数组里的类型的。
|
21
xiaoming1992 OP @zbinlin 对,被搞懵了
|
22
Oucreate 2019-08-28 13:47:12 +08:00 1
@azh7138m #4
> entries 定义是 > entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][] 虽然的确如此(可见于文件`lib.es2017.object.d.ts`),但我想不出需要 `<T>` 的情形,你能不能举个例子?谢谢啦! |
24
xiaoming1992 OP |
25
Oucreate 2019-08-28 15:08:52 +08:00 1
|
26
Oucreate 2019-08-28 15:12:15 +08:00
修正:
“毕竟值不都是任意类型的么” → “毕竟值不都 *可以* 是任意类型的么” |
27
azh7138m 2019-08-28 15:45:31 +08:00
|
28
lhc70000 2019-08-28 16:17:15 +08:00
```
```ts type Vegetable = "茄子" | "黄瓜" | "西红柿"; type Value = { price: number, num: number }; const list: Record<Vegetable, Value> = { "茄子": { price: 5, num: 2 }, "西红柿": { price: 5, num: 2 }, "黄瓜": { price: 5, num: 2 }, }; (Object.entries(list) as [Vegetable, Value][]).map(([key, item]) => { // ... }); ``` 要是我的话就这么写。 或者就直接使用 Map,这样 list.entries() 能保持 key 的类型。 |
31
xiaoming1992 OP |