实现代码
type DeepTransform<T> = T extends string[]
? number[]
: T extends Array<infer U>
? Array<DeepTransform<U>>
: T extends object
? {
[K in keyof T]: DeepTransform<T[K]>;
}
: T;
function deepTransform<T>(obj: T): DeepTransform<T> {
if (Array.isArray(obj)) {
if (obj.length === 0 || typeof obj[0] === 'string') {
return obj.map(str => (typeof str === 'string' ? str.length : 0)) as DeepTransform<T>;
} else {
return obj.map(item => deepTransform(item)) as DeepTransform<T>;
}
} else if (typeof obj === 'object' && obj!== null) {
const result: any = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
result[key] = deepTransform(obj[key]);
}
}
return result;
}
return obj;
}
性能考虑
- 减少递归深度:在
deepTransform
函数中,对于数组类型,首先判断其元素是否为字符串。如果是,则直接进行转换,避免不必要的递归。这样可以减少递归调用栈的深度,提高性能。
- 缓存结果:对于一些重复出现的子结构,可以考虑使用缓存机制。不过在这种通用的类型转换场景中,由于对象结构的多样性,缓存实现较为复杂且收益不一定高,这里暂未实现。
避免类型爆炸
- 限制泛型深度:在定义
DeepTransform
类型时,虽然没有明确限制泛型递归的深度,但通过 if - else
逻辑在运行时避免了无限递归。例如,对于非对象和非数组类型直接返回原类型,避免了进一步的类型扩展。
- 避免过度嵌套泛型:在设计类型转换逻辑时,尽量使用简单的泛型嵌套结构。例如,只在对象和数组类型上进行递归,而不是在更多复杂的类型组合上嵌套泛型,这样可以减少类型计算的复杂度,避免类型爆炸。