How to correctly traverse an object in Ts
Article first published on personal blog
This is a short essay...
JavaScript
Before explaining how to traverse an object with Ts, let's talk about how to implement it in Js, for...in
, Object.keys
, a simple example:
// for...in
const obj = {
name: 'itsuki',
address: 'hangzhou',
};
for (const key in obj) {
console.log(key, obj[key].toUpperCase());
}
// Object.keys
Object.keys(obj).forEach(key => {
console.log(key, obj[key].toUpperCase());
});
// 输出
// name ITSUKI
// address HANGZHOU
复制代码
TypeScript
for...in
But in TypeScript, if you use it directly, you will find an error.
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)
复制代码
What we know for...in
and Object.keys
get is the key of the object, and all keys in the object are strings, so it cannot be assigned Person
to name
, address
.
But we can keyof
solve this problem.
function print(obj:Person){
let key: keyof Person;
for (key in obj) {
// ✅
console.log(key, obj[key].toUpperCase());
}
}
复制代码
Object.keys
When used Object.keys
, we can use as
operators to solve.
function print(obj: Person) {
Object.keys(obj).forEach((k) => {
// ✅
console.log(k, obj[k as keyof Person].toUpperCase());
});
}
复制代码
We can abstract this out into a function:
function getKeys<T>(obj: T) {
return Object.keys(obj) as Array<keyof T>;
}
getKeys(obj); // (keyof Person)[]
复制代码
Object.entries
We can also use Object.entries()
to iterate over objects.
Object.entries(obj).forEach(([k, v]) => {
console.log(k, v);
});
复制代码
think
The following is my own thinking, if I am wrong, please correct me
What I want to Object.keys()
return is one string[]
because it is determined at runtime and we know TypeScript
it's just a static type check, even if we use keyof Person
return name | address
, but we can't be sure at runtime it's the two fields.
For example:
const obj2 = {
name: 'itsuki',
address: 'hangzhou',
age: 20,
};
print(obj2)
// 编译时: ✅, 因为它有name、address属性
// 运行时: ❌, 因为age字段是number, 没有toUpperCase方法
复制代码
Then I found this sentence in the Github issue:
Types in TS are open ended. Therefore,
keysof
there may be less than all properties obtained at runtime.
It made me understand even more why it was keys()
returning one string[]
instead of one (keyof Person)[]
.