I was made texteditor in vue3 + vite + ts, with tiptap, but in item.type
, item.icon
... all item attributes say 'error'
.
That say ToolbarItem | Divider
not have each other attributes:
item.type => Property 'type' does not exist on type 'ToolbarItem | Divider', Property 'type' does not exist on type 'ToolbarItem'
,
My code in parents component:
<template v-for="(item, index) in items" :key="index">
<div v-if="item.type === 'divider'" class="divider" :key="`divider${index}`" />
<Child v-else :key="index"
:icon="item.icon" :title="item.title"
:action="item.action" :isActive="item.isActive"/>
</template>
interface ToolbarItem {
icon: string,
title: string,
action: Function,
isActive?: Function
}
interface Divider {
type: string
}
const items: Array<ToolbarItem | Divider> = [
{
icon: 'bold',
title: 'Bold',
action: () => props.editor.commands.toggleBold(),
isActive: () => props.editor.isActive('bold'),
},
{
type: 'divider'
},
...
]
My code in Child component:
interface ToolbarButtonProps {
icon: string,
title: string,
action: Function,
isActive?: Function
}
const props = defineProps<ToolbarButtonProps>()
I hope to separatly inject items to div or Child and stop see error message
that say ToolbarItem | Divider not have each other attributes
Like the error suggests, your array of objects do not have similar properties. JavaScript allows you to access properties that do not exist in an object. For ex:
const fruit = { shape: 'round', color: 'red' };
console.log(fruit.size); // undefined
Now, while JavaScript allows this, we shouldn't just use it. It becomes harder to read the code since you'd expect that fruit.size
returns the value of size
, but it results to undefined
instead. This is why TypeScript is complaining.
There are a couple of ways to address the TypeScript issue, however, perhaps we can try re-thinking how we create our template.
<template v-for="(item, index) in items" :key="index">
<div v-if="item.type === 'divider'" class="divider" :key="`divider${index}`" />
<Child v-else :key="index"
:icon="item.icon" :title="item.title"
:action="item.action" :isActive="item.isActive"/>
</template>
Looking at this code, it seems the purpose of the div
element is to add some sort of divider or margin between each rendered Child
component. Try reworking it this way:
<template>
<section v-for="(item, index) in items" :key="index">
<Child
:key="index"
:action="item.action"
:icon="item.icon"
:isActive="item.isActive"
:title="item.title"
/>
<div
v-if="index < items.length"
:key="`divider${index}`"
class="divider"
/>
</section>
</template>
With this, you don't need a "divider" in items
and you don't need to conditionally render Child
:
const items: Array<ToolbarItem> = [
{
icon: 'bold',
title: 'Bold',
action: () => props.editor.commands.toggleBold(),
isActive: () => props.editor.isActive('bold'),
},
...
]
Here is an example.