英文:
How to Iterate through heterogenous object in Typescript
问题
- 在这种情况下,有办法帮助 TypeScript 正确推断类型吗?
- 有没有更好的方法来实现我想要完成的任务?
【代码部分不进行翻译】
英文:
I have a state object and an update object that will be combined with the state object, though null
in the update means delete so I can't just do {...a, ...b}
with them.
const obj = {
other: new Date(),
num:5,
str:"original string"
}
const objUpdate:Partial<typeof obj> = {
num:6,
str:"updated string"
}
The task: Iterate through the update object and apply its values to the original object. This is how I ideally would do it:
Object.entries(objUpdate).forEach(([k,v])=>{
if (v === undefined) return;
if (v === null){
delete obj[k]; // <-
return;
}
obj[k] = v; // <-
})
But at the indicated lines I get an error that No index signature with a parameter of type 'string' was found on type '{ other: Date; num: number; str: string; }'
. Ideally Typescript would know that k
is already keyof typeof objUpdate
(edit: here's possibly why) but I guess I can explicitly indicate that:
Object.entries(objUpdate).forEach(([k,v])=>{
if (v === undefined) return;
if (v === null){
delete obj[k as keyof typeof objUpdate];
return;
}
obj[k as keyof typeof objUpdate] = v; // <-
})
At the indicated line it complains that Type 'string | number | Date' is not assignable to type 'never'. Type 'string' is not assignable to type 'never'.
- Is there a way to help Typescript infer typings correctly in this situation?
- Is there a better approach to what I am trying to accomplish?
答案1
得分: 1
在JavaScript中,动态删除对象上的键既慢又可能会让TypeScript的类型检查更加困难。最简单的方法是调整代码中引用状态的其他部分,以便它们检查值是否为 null
。因此,不要像这样拥有一个状态对象:
const obj = {
other: <someDate>,
str: <someString>
}
而应该是这样的:
const obj = {
other: <someDate>,
num: null,
str: <someString>
}
使用这种方法,类型检查将正常工作,状态更新将像 {...a, ...b}
一样简单。
为了为初始状态定义类型,将键映射到一个带有 null
的新对象类型中。
const obj = {
other: new Date(),
num: 5,
str: "original string"
}
type Obj = typeof obj;
type ObjState = {
[K in keyof Obj]: Obj[K] | null;
};
// ...
const [stateObj, setStateObj] = useState<ObjState>(obj);
// 更新:
setStateObj({ ...stateObj, ...objUpdate });
如果代码的某部分要求对象在格式化时去除 null
属性(例如用于数据库查询),请在必要时创建一个新对象,然后再发送该对象,而不是更改状态的形状。
const objWithNullPropertiesRemoved: Partial<Obj> = Object.fromEntries(
Object.entries(stateObj)
.filter(([, val]) => val !== null)
);
// 将 objWithNullPropertiesRemoved 发送到某个地方
英文:
Dynamically deleting keys on an object is both slow in JavaScript and can make typing more difficult in TypeScript. The easiest way to approach this by a good margin would be to tweak the other parts of your code that reference the state so that they check if the value is null
or not. So, instead of having a state object of
const obj = {
other: <someDate>,
str: <someString>
}
there would be
const obj = {
other: <someDate>,
num: null,
str: <someString>
}
Using this approach, typing will just work, and the state update will be as trivial as {...a, ...b}
.
To type the initial state, map the keys to a new object type with null
added in.
const obj = {
other: new Date(),
num:5,
str:"original string"
}
type Obj = typeof obj;
type ObjState = {
[K in keyof Obj]: Obj[K] | null;
};
// ...
const [stateObj, setStateObj] = useState<ObjState>(obj);
// Update:
setStateObj({ ...stateObj, ...objUpdate });
If some part of the code requires the object to be formatted with the null
properties removed (such as for a database query), do that by creating a new object when it's necessary, just before sending the object, rather than changing the state's shape.
const objWithNullPropertiesRemoved: Partial<Obj> = Object.fromEntries(
Object.entries(stateObj)
.filter(([, val]) => val !== null)
);
// send the objWithNullPropertiesRemoved somewhere
答案2
得分: 0
我接受的答案很可能是大多数人正确的方法,但我刚刚找到了一种使我的原始方法工作并在这里提供的方法。
使用https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type,然后将值v键入as UnionToIntersection<typeof obj[keyof typeof obj]>
。
英文:
The answer I accepted is most likely the correct approach for most people but I just found a way to get my original approach to work and provide it here for completeness.
Using https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type I then typed the value v as as UnionToIntersection<typeof obj[keyof typeof obj]>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论