-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamic slot using v-for with typescript implicitly has type 'any' #5312
Comments
After some further testing this behavior seems to be coming from the components definition file that is automatically generated as part of the vitesse template. This doesn't make it a vitesse specific issue as I was able to recreate the bug on a vue-cli project as well. It seems that when a vue file containing this pattern is added to a definition file like so: declare module 'vue' {
export interface GlobalComponents {
Table: typeof import('./components/tabletest/Table.vue')['default']
}
} Typescript doesn't understand how to read the file. Unfortunately, I am only just learning how typescript works and am completely unqualified to know how to fix this problem beyond just removing and blacklisting that particular file from being in a typescript definition, which isn't exactly ideal. This pattern should work regardless of an entry in a definition file. |
I'm also running into this, and have found a workaround. The problem occurs when there are both static and dynamic slot names. In this situation, the slots are incorrectly typed using only the static names. To side-step the issue, we can define our static slots dynamically. One note about this, we have to use a template string to avoid typing the name as a string literal, see here for an example <!-- before -->
<slot name="foobar" />
<!-- after -->
<slot :name="`${'foobar'}`" /> |
Same issue happens when you try to pass couple of slots to a child component that uses dynamic slot names. No current workarounds so far <!--
Element implicitly has an 'any' type because
expression of type 'string | number' can't be used to index type
-->
<template
v-for="(_, slot) of $slots"
#[slot]="data" <!-- error is here -->
>
<slot
:name="slot"
:item="data?.item"
/>
</template> |
Wow, same issue here. I am looping over the slots to render them dynamically, and getting the same complaint from Typescript @the94air |
@Kasopej the main cause of this issue is that |
My case is a bit different from yours, but 'defineSlots' worked for me @the94air
|
@seregarom that looks neat. I'll give it a try. Thanks for sharing! |
Vue 3.3.5 <template
v-for="(name, index) of (Object.keys($slots) as {})"
OR
v-for="(_, name, index) in ($slots as {})"
v-slot:[name]="scope"
:key="index"
>
<slot :name="name" v-bind="{ scope }"></slot>
</template> Full error: |
The latest suggested proposal does not seems to do the trick on my side. I've been able to get rid of almost all of my 120 errors, two are remaining, due to.. dynamic slot names :) Any chance a month later? |
same error in typescript as @NojusM |
Not sure if this is related but also get an error when trying to compile this non-ts code.
|
Vue 3.4 ReHelloWorld.vue<script setup lang="ts">
import HelloWorld from './HelloWorld.vue'
interface Slots {
default: (props: { default: string }) => string
top: (props: { top: number }) => string
bottom: (props: { bottom: boolean }) => string
}
defineSlots<Slots>()
</script>
<template>
<HelloWorld>
<template v-for="(_, name) in $slots as unknown as Readonly<Slots>" #[name]="slotProps">
<slot :name="name" v-bind="slotProps" />
</template>
</HelloWorld>
</template> It looks fine but I have a type error. Argument of type '{ default: string; } | { top: number; } | { bottom: boolean; }' is not assignable to parameter of type '{ default: string; } & { top: number; } & { bottom: boolean; }'.
Type '{ default: string; }' is not assignable to type '{ default: string; } & { top: number; } & { bottom: boolean; }'.ts(2345) |
Thanks @NojusM your snippet resolved the issue I was having. |
How to fix it in current project? |
with a combination of |
Getting a similar error with
A simplified version of my components follow: <!-- Table.vue -->
<template>
<table>
<tbody>
<tr v-for="(item, index) of items" :key="item">
<td v-for="column of columns" :key="column.id" >
<slot :name="column.id" :item="item" :index="index" />
</td>
</tr>
</tbody>
</table>
</template>
<script setup lang="ts">
export interface Column {
id: string;
title: string;
}
interface IProps {
columns: Column[];
items: any;
}
defineProps<IProps>();
</script> <!-- PlayerTable.vue -->
<Table :columns="columns" :items="rounds">
<template v-for="player of players" v-slot:[player.id]="slotProp" :key="`${slotProp.item.id}-${player.id}`">
<SomeComponent :info="slotProp.info[player.id]" />
</template>
</Table>
</template>
<script setup lang="ts">
// ... imports and etc
const rounds = computed(() =>[
{ round: 1, info: { player1: "foo", player2: "bar" }}
]);
const columns = computed<Column[]>(() => {
return [
{
id: "round",
title: "Round",
},
...players.value.map((player) => {
return {
id: player.id,
title: player.name,
};
}),
];
});
</script> The error I get is Property 'slotProp' does not exist on type 'CreateComponentPublicInstanceWithMixins<ToResolvedProps<IProps, {}>, { Table: typeof Table; PlayerTable: typeof PlayerTable; PlayerIcon: typeof PlayerIcon; players: typeof players; rounds: typeof rounds; columns: typeof columns; }, ... 23 more ..., {}>'.
17 <template v-for="player of players" v-slot:[player.id]="slotProp" :key="`${slotProp.item.id}-${player.id}`"> |
As @NojusM suggested, the following does the trick:
Cast |
It doesn't work in my case with Note: This only happens if I upgrade <script setup lang="ts">
import DefaultTheme from 'vitepress/theme'
</script>
<template>
<DefaultTheme.Layout>
<template v-for="(_, slot) in $slots" #[slot]="scope">
<!-- ^^^^ slot implicitly has type any because it does not have a type annotation and is referenced directly or indirectly in its own initializer. -->
<slot :name="slot" v-bind="scope" />
</template>
</DefaultTheme.Layout>
</template> |
|
Version
3.2.28
Reproduction link
github.com
Steps to reproduce
Clone the repo,
open folder in VSCode,
I have included a dev container that npm installs pnpm and vuenext and the volar extension,
once in dev container (or on host if you prefer) run pnpm install
Optionally run pnpm dev to start vite and open the page to see the rendered table.
What is expected?
For Typescript to not return an error.
What is actually happening?
Typescript is returning an error in (src/components/tabletest/Table.vue) line 84:
https://github.com/Moonlight63/temp-vue-typescript-bug/blob/e723dcd5905bb84f23dd67da3a15f3c465db4ae3/src/components/tabletest/Table.vue#L84
The error is:
'column' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
'column' is created by a v-for loop over a computed property of columns. The type should be inferred, and it normally is. This error only appears when I use any property of column to set the name of the slot dynamically.
I initially thought this was just an eslint error, so I opened an issue with the eslint vue plugin that has more info with pictures:
vuejs/eslint-plugin-vue#1773
Also worth noting. The component renders perfectly fine and everything works as expected, with the exception that in the app where I am actually using this functionality my build configuration won't allow the error. Because the error is occurring in the template, I can't just assert the type or otherwise tell typescript to ignore that line (that I know of).
The text was updated successfully, but these errors were encountered: