N
Nuxt5mo ago
___anj___

Typing dynamic template refs in a loop

So I was working on some unrelated type refactoring and once I fixed some typing issue, another one arrised. And since it is a little bit non-standard code from around 2 years ago, I wonder how to go about it. So basically we have a carousel like this (I simplified it a bit and omitted unrelated props)
<template>
<SimpleCarousel :carousel-items="galleryItems">
<template #default="{ currentItem, index }">
<img :ref="`carouselItem${index}`">
</template>
<template #custom-last-item>
<iframe :ref="`carouselItem${galleryItems.length}`" />
</template>
</SimpleCarousel>
</template>
<template>
<SimpleCarousel :carousel-items="galleryItems">
<template #default="{ currentItem, index }">
<img :ref="`carouselItem${index}`">
</template>
<template #custom-last-item>
<iframe :ref="`carouselItem${galleryItems.length}`" />
</template>
</SimpleCarousel>
</template>
As you can see we are assigning refs to elements rendered in a loop (they are slotted into a component that renders them in a loop). And inside the component I'm working on we are getting an active index as a prop:
props: {
activeIndex: {
type: Number,
required: true,
validator: (activeIndex: number) => activeIndex >= 0
},
},
props: {
activeIndex: {
type: Number,
required: true,
validator: (activeIndex: number) => activeIndex >= 0
},
},
Then using said index we are getting ref of a current item via a function:
const activeCarouselRef = () => {
return refs[`carouselItem${props.activeIndex}`] as HTMLElement;
};
const activeCarouselRef = () => {
return refs[`carouselItem${props.activeIndex}`] as HTMLElement;
};
And using this active ref for example like this:
imgPosition.x = activeCarouselRef().getBoundingClientRect().x;
imgPosition.x = activeCarouselRef().getBoundingClientRect().x;
or like this:
activeCarouselRef().style = '...'
activeCarouselRef().style = '...'
Apparently it is working fine. At least at runtime. But typescript has a problem with it saying:
Property 'getBoundingClientRect' does not exist on type 'Element | Vue | Vue[] | Element[]'.
Property 'getBoundingClientRect' does not exist on type 'Vue'.Vetur(2339)
Property 'getBoundingClientRect' does not exist on type 'Element | Vue | Vue[] | Element[]'.
Property 'getBoundingClientRect' does not exist on type 'Vue'.Vetur(2339)
Property 'style' does not exist on type 'Element | Vue | Vue[] | Element[]'.
Property 'style' does not exist on type 'Element'.Vetur(2339)
Property 'style' does not exist on type 'Element | Vue | Vue[] | Element[]'.
Property 'style' does not exist on type 'Element'.Vetur(2339)
Sooo... now I'm not sure how to proceed. Do you have an idea?
1 Reply
___anj___
___anj___5mo ago
I could just slap the as keyword:
return refs[`carouselItem${props.activeIndex}`] as HTMLElement;
return refs[`carouselItem${props.activeIndex}`] as HTMLElement;
And red squiggly lines will magically go away. But I'm not sure if it is really correct typing and anyway I want to avoid using as as much as possible (pun not intended). Do you have an idea how to overcome it? What would be a good refactor to make here?
Want results from more Discord servers?
Add your server