Reputation: 29
I have a vue3 component. It shows list of items. And there is a function to delete item. The problem is that i need check param, and write in which array apply filter. I want to make common function to do this with typescript.
<template>
<div v-for="cat in items.cats" :key="cat.id" :style="{ display: ' flex' }">
<div>{{ cat }}</div>
<button type="button" @click="deleteItem('cats', cat.id)">delete</button>
</div>
<div v-for="car in items.cars" :key="car.id" :style="{ display: ' flex' }">
<div @delete="deleteItem('cars', car.id)">{{ car }}</div>
<button type="button" @click="deleteItem('cars', car.id)">delete</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
interface Common {
id: number;
}
interface Cat extends Common {
name: string;
type: string;
}
interface Car extends Common {
model: string;
serial: string;
}
interface Item {
cats: Cat[];
cars: Car[];
anotherArray: [];
oneMoreArray: [];
oneKey: string;
}
const items = ref<Item>({
cats: [
{
id: 0,
name: 'Kitty',
type: 'home',
},
{
id: 1,
name: 'Sherhan',
type: 'jungle',
},
],
cars: [
{
id: 0,
model: 'BMW',
serial: 'X5',
},
{
id: 1,
model: 'Audi',
serial: 'Q5',
},
],
anotherArray: [],
oneMoreArray: [],
oneKey: '',
});
function deleteItem(name?: 'cats' | 'cars', id?: number) {
if (id !== undefined && name === 'cats') {
items.value.cats = items.value.cats?.filter((cat: Cat) => cat.id !== id);
}
if (id !== undefined && name === 'cars') {
items.value.cars = items.value.cars?.filter((car: Car) => car.id !== id);
}
}
</script>
this is my solution, with using keyof Item
<script setup lang="ts">
function myFunc<T>(entity: keyof Item, id?: number) {
if (id) {
(items.value[entity] as T[]) = (items.value[entity] as T[]).filter((item: Common) => item.id !== id);
}
} // and here i got an error: No overload matches this call.
</script>
<template>
<div v-for="cat in items.cats" :key="cat.id" :style="{ display: ' flex' }">
<div>{{ cat }}</div>
<button type="button" @click="deleteItem < Cat > ('cats', cat.id)">delete</button>
</div>
<div v-for="car in items.cars" :key="car.id" :style="{ display: ' flex' }">
<div>{{ car }}</div>
<button type="button" @click="deleteItem < Car > ('cars', car.id)">delete</button>
</div>
</template>
think must be better solution with more features of typescript
Upvotes: 2
Views: 311
Reputation: 370
The only problem here is that oneKey
is defined as a string
. Rest all attributes are of type array
. Thats the reason you cannot do (items.value[entity] as T[])
. Coz not everything is an array. If you keep oneKey
in a separate type, this can be accomplished by
const deleteItems = (item: Item, name: keyof Item, id: Common['id']): Item => ({
...items,
[name]: items[name].filter((d: Common) => d.id !== id),
});
Always prefer immutability
. This keeps the function deleteItems
pure and you can re-assign the returned values
Upvotes: 1