I have a generic function which removes properties from object and returns a new one. However if the object has a nested array of objects ts starts to complain. How can I solve this problem?
interface User {
id: number;
name: string;
items?: User[];
}
const user: User = {
id: 1,
name: 'test',
items: [
{
id: 1,
name: 'item',
},
],
};
function transformObject<T>(fields: (keyof T)[], obj: T): T {
const newObject = {} as T;
for (const key in obj) {
if (!fields.includes(key)) {
newObject[key] = obj[key];
}
if (Array.isArray(obj[key])) {
newObject[key] = [];
for (let j = 0; j < obj[key].length; j ) {
newObject[key].push(transformObject(fields, obj[key][j]));
}
}
}
return newObject;
}
const result = transformObject(['id'], user);
console.log(result);
CodePudding user response:
You have two problems here.
TypeScript is not powerful enough to realise that newObject[key]
should be of type array when obj[key]
is an array. You'll have to manually infer the type since undefined[] does not necessarily exist on type T
.
newObject[key] = [] as unknown as T[typeof key];
Furthermore you can't check a type on an item in an array if you need that type information, because TypeScript is not powerful enough to keep track of that.
Instead of checking if obj[key]
is of type array, move this into a new variable and then perform the checks
const val = obj[key];
if (Array.isArray(val)) {
newObject[key] = [] as unknown as T[typeof key];
for (let j = 0; j < val.length; j ) {
newObject[key].push(transformObject(fields, obj[key][j]));
}
}
and lastly newObject[key]
is not necessarily an array and you therefore need to explicitly tell TypeScript what type it is
(newObject[key] as undefined as T[]).push(transformObject(fields, obj[key][j]));
There might be a great solution here where types are inferred and everything just works, but sometimes, especially when we're dealing with generic type recursion, you'll just need to cast types.