TypeScript 不正确地推断类型?

huangapple go评论62阅读模式
英文:

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&lt;T extends object&gt;(obj: T): T {
	const newInstance = { ...obj };
	const keys = Object.keys(newInstance);
	keys.forEach(key =&gt; {
		if (typeof newInstance[key as keyof object] === &#39;function&#39;) {
			return;
		}

		if (typeof newInstance[key as keyof object] === &#39;object&#39;) {
			newInstance[key as keyof object] = clearObject&lt;object&gt;(newInstance[key as keyof object]);
		}
	});
	return obj;
}

On the line:

newInstance[key as keyof object] = clearObject&lt;object&gt;(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;
        }
    }
}

应该提供了一种很好的递归处理传递的任何类型的方式。

Playground 链接

英文:

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&lt;T&gt;(obj: T): T {
    switch (typeof obj) {
        case &quot;object&quot;:
            {
                // null is an object
                if (obj == null) {
                    return obj;
                }
                // arrays are objects
                if (Array.isArray(obj)) {
                    return obj.map(clearObject) as T
                }
                // &quot;normal&quot; objects
                return Object.fromEntries(
                    Object.entries(obj).map(([k, v]) =&gt; [k, clearObject(v)])
                ) as T
            }
        default: {
            return obj;
        }
    }
}

should provide a nice way to recurse through whatever is passed.

Playground Link

huangapple
  • 本文由 发表于 2023年3月3日 18:32:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75625940.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定