Case #1
@kaya3's comment is correct. Your function assumes that your array elements and your item variable (both type T) will have a .name property. So you must ensure that all possible types for T include at least a name.
function test1<T extends { name: any }>(arr: Array<T>, item: T) {
const idxReplaced = arr.findIndex(element => element.name === item.name)
return [
...arr.slice(0, idxReplaced),
...arr.slice(idxReplaced + 1)
]
}
You don't need to set the generic here because it is inferred as <{name: number}> based on the arguments.
console.log(test1([{ name: 1 }, { name: 3 }], { name: 3 }))
Case #2
function test<IItem>(arr:Array<IItem>, item:IItem) {
This right here shows a misunderstanding of generic type parameters. You can use any name for the generic type and <IItem> here is basically <T> with another name. It is a local type variable that bears no relation to the interface IItem.
I suspect what you meant to do was something like this, where the generic type must extend {user: string}:
function test2<T extends IItem>(arr: Array<T>, item: T) {
Or to not have it be generic at all, and simply add types to the arguments:
function test2(arr: Array<IItem>, item: IItem) {
We are building an object acc where the key is a string from the item's user property and the value is an item. You've got that part typed correctly. It's fine to access acc[el.user] because acc has a string index.
But what are you trying to to do with item[el.user]? el.user is the username string and item is an IItem. It does not have a property that corresponds to the user value.
In your example:
console.log(test2([{ user: 'info' }, { user: 'test' }], { user: 'some info' }))
You would be accessing ({ user: 'some info' }).info and ({ user: 'some info' }).test. Typescript is right to warn you that those don't exist.
I'm genuinely not sure what you are trying to achieve here. If you meant to turn an array of items into an object keyed by the username then you don't need a second argument item for that. That would be:
interface IItem {
user: string,
}
interface ICurrentItem<T extends IItem> {
[key: string]: T
}
function test2<T extends IItem>(arr: Array<T>) {
return arr.reduce((acc: ICurrentItem<T>, el: T) => {
acc[el.user] = el
return acc
}, {})
}
console.log(test2([{ user: 'info' }, { user: 'test' }]))
Typescript Playground Link
edit: "I want to change every name property in object array according its name."
I think maybe you want map instead of reduce?
This code replaces the user property of the array elements with the user property from item.user ("some info").
function test<T extends IItem>(arr: Array<T>, item: T) {
return arr.map(el => ({ ...el, user: item.user }));
}
console.log(test([{ user: 'info' }, { user: 'test' }], { user: 'some info' }))
// output: [{ "user": "some info" }, { "user": "some info" }]
Tan upper bound, like<T extends {name: string}>.console.log(test([{user:'info'},{user:'test'}], {user: 'some info'}). I can explain the error but I don't understand what you want it to do.