英文:
TypeScript does not correctly infer type?
问题
问题描述
我想要一个具有通用返回类型的函数,该函数遍历给定对象并对每个对象值执行一些操作。
示例
我有一个函数:
function clearObject<T extends object>(obj: T): T {
const newInstance = { ...obj };
const keys = Object.keys(newInstance);
keys.forEach(key => {
if (typeof newInstance[key as keyof object] === 'function') {
return;
}
if (typeof newInstance[key as keyof object] === 'object') {
newInstance[key as keyof object] = clearObject<object>(newInstance[key as keyof object]);
}
});
return obj;
}
在以下这行代码上:
newInstance[key as keyof object] = clearObject<object>(newInstance[key as keyof object]);
TS检测到错误:
TS2322:类型“object”无法赋给类型“never”。
为什么?在上面的条件中,我正在验证newInstance[key]
的类型为*'object'*。这是TypeScript的问题吗?我正在使用最新版本4.9。
英文:
Problem description
I want to have a function with generic return type which iterates through given object and do some operations with each of object values.
Example
I have a function:
function clearObject<T extends object>(obj: T): T {
const newInstance = { ...obj };
const keys = Object.keys(newInstance);
keys.forEach(key => {
if (typeof newInstance[key as keyof object] === 'function') {
return;
}
if (typeof newInstance[key as keyof object] === 'object') {
newInstance[key as keyof object] = clearObject<object>(newInstance[key as keyof object]);
}
});
return obj;
}
On the line:
newInstance[key as keyof object] = clearObject<object>(newInstance[key as keyof object]);
TS detects an error:
> TS2322: Type 'object' is not assignable to type 'never'.
Why? In above condition, I am verifying that newInstance[key]
is of type 'object'. Is this issue of TypeScript? I am using the newest release, 4.9.
答案1
得分: 2
以下是代码部分的中文翻译:
这种对象的递归“重建”很难同时保持类型系统的稳定性。有时候,强制类型转换是不可避免的。
与其决定是否安全递归调用函数,也许更好的做法是允许函数接受任何类型的参数,然后相应地处理。如下所示:
function clearObject<T>(obj: T): T {
switch (typeof obj) {
case "object":
{
// null 是一个对象
if (obj == null) {
return obj;
}
// 数组是对象
if (Array.isArray(obj)) {
return obj.map(clearObject) as T;
}
// "正常"对象
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, clearObject(v)])
) as T;
}
default: {
return obj;
}
}
}
应该提供了一种很好的递归处理传递的任何类型的方式。
英文:
These sorts of recursive "rebuilds" of an object are very hard to get right while also keeping the type-system happy. Sometimes casts are inevitable.
Rather than having to decide whether it is safe to recursively call your function, it's probably better to allow the function to accept any type and then to deal with it appropriately. As such:
function clearObject<T>(obj: T): T {
switch (typeof obj) {
case "object":
{
// null is an object
if (obj == null) {
return obj;
}
// arrays are objects
if (Array.isArray(obj)) {
return obj.map(clearObject) as T
}
// "normal" objects
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, clearObject(v)])
) as T
}
default: {
return obj;
}
}
}
should provide a nice way to recurse through whatever is passed.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论