2022-03-27 上午发布2,012 次点击1 条评论需阅读4分钟
在 Ts 中如何正确的遍历一个对象
这是一篇小短文...
JavaScript
在讲解用 Ts 遍历一个对象之前, 我们先说说 在 Js 中怎么实现,
for...in
、Object.keys
, 一个简单的例子:// for...inconst obj = {name: 'itsuki',address: 'hangzhou',};for (const key in obj) {console.log(key, obj[key].toUpperCase());}// Object.keysObject.keys(obj).forEach(key => {console.log(key, obj[key].toUpperCase());});// 输出// name ITSUKI// address HANGZHOU
TypeScript
for...in
但是在 TypeScript 中, 如果你直接这么用的话, 发现会报错.
type Person = {name: string;address: string;};const obj: Person = {name: 'itsuki',address: 'hangzhou',};function print(obj: Person) {for (const key in obj) {// ❌// key:string 不能分配给 { name:string; age:number }类型console.log(key, obj[key].toUpperCase());}}print(obj)
我们知道
for...in
、Object.keys
拿到的是对象的 key, 而在对象中所有的 key 都是字符串, 所以它无法分配给Person
的name
、address
.但是我们可以
keyof
来解决这个问题.function print(obj:Person){let key: keyof Person;for (key in obj) {// ✅console.log(key, obj[key].toUpperCase());}}
Object.keys
在使用
Object.keys
时, 我们可以使用as
运算符来解决.function print(obj: Person) {Object.keys(obj).forEach((k) => {// ✅console.log(k, obj[k as keyof Person].toUpperCase());});}
我们可以把这个抽离出一个函数:
function getKeys<T>(obj: T) {return Object.keys(obj) as Array<keyof T>;}getKeys(obj); // (keyof Person)[]
Object.entries
我们也可以使用
Object.entries()
来遍历对象.Object.entries(obj).forEach(([k, v]) => {console.log(k, v);});
思考
以下是我自己的思考, 如有错误, 请指正
我想
Object.keys()
返回的是一个string[]
, 是因为它是在运行时确定的, 我们知道TypeScript
做的只是静态类型的检查, 即使我们使用keyof Person
返回了 name | address
, 但是我们不能肯定在运行时它就是这两个字段.比如说:
const obj2 = {name: 'itsuki',address: 'hangzhou',age: 20,};print(obj2)// 编译时: ✅, 因为它有name、address属性// 运行时: ❌, 因为age字段是number, 没有toUpperCase方法
然后我在 Github issue 里面找到这一句话:
TS 中的类型是开放式的。因此,keysof
可能会少于在运行时获得的所有属性。
它更要我明白了, 为什么
keys()
返回的是一个string[]
, 而不是一个(keyof Person)[]
.