-
-
Notifications
You must be signed in to change notification settings - Fork 508
Description
Vue - Official extension or vue-tsc version
2.2.8
VSCode version
not using VSC
Vue version
3.5.13
TypeScript version
5.8.3
System Info
System:
OS: Windows 11 10.0.26100
CPU: (16) x64 AMD Ryzen 7 5700G with Radeon Graphics
Memory: 10.47 GB / 27.90 GB
Binaries:
Node: 23.5.0 - C:\Program Files\nodejs\node.EXE
Yarn: 4.5.1 - ~\AppData\Roaming\npm\yarn.CMD
npm: 9.7.2 - C:\Program Files\nodejs\npm.CMD
pnpm: 8.3.1 - ~\AppData\Local\pnpm\pnpm.EXE
Browsers:
Edge: Chromium (131.0.2903.86)
Internet Explorer: 11.0.26100.1882package.json dependencies
{
"dependencies": {
"vue": "3.5.13"
},
"devDependencies": {
"@tsconfig/node22": "22.0.1",
"@types/node": "22.14.0",
"@vitejs/plugin-vue": "5.2.3",
"@vue/tsconfig": "0.7.0",
"npm-run-all2": "7.0.2",
"typescript": "5.8.3",
"vite": "6.2.4",
"vite-plugin-vue-devtools": "7.7.2",
"vue-tsc": "2.2.8"
}
}Steps to reproduce
I've created a simple Vue component with a generic set: T extends ({id: string} & Record<string, unknown>)
The actual type is passed implicitly by a prop:
const props = defineProps({
data: {
type: Object as PropType<T[]>,
required: true
},
columns: {
type: Array as PropType<(keyof T & string)[]>,
required: true
}
})Based on the generic, defineSlots is used to define slots:
defineSlots<{
[K in keyof T as `header-${K & string}`]: () => unknown
} & {
[K in keyof T as `cell-${K & string}`]: (props: { value: T[K], item: T }) => unknown
} & {
"header-__action": () => unknown,
"cell-__action": (props: { item: T }) => unknown
}>()And used for the actual rendering:
<th v-for="column in props.columns" :key="column">
<slot v-if="$slots[`header-${column}`]" :name="`header-${column}`"></slot>
<template v-else>{{ column }}</template>
</th>
<th v-if="$slots['cell-__action']">
<slot v-if="$slots['header-__action']" name="header-__action"></slot>
<template v-else>Actions</template>
</th>
<slot v-if="$slots[`cell-${column}`]" :name="`cell-${column}`" :value="row[column]" :item="row"></slot>
<slot name="cell-__action" :item="row as T"></slot>(see the referenced link to the minimal reproduction)
Finally used in my page to render data:
const data = [
{
id: 'first',
name: 'John Doe',
married: false
},
// ....
]<GenericTable :columns="['name', 'married']" :data="data">
<template #header-married>Is married?</template>
<template #cell-married="{value}">{{ value ? 'Yes' : 'No' }}</template>
<template #cell-__action>
<a>Show more info</a>
</template>
</GenericTable>The rendering works without any issues:

But the type-check fails.
What is expected?
The type-check should not fail at the slot calls (with dynamic and static names)
What is actually happening?
The type-check fails at every single slot in the template
src/components/GenericTable.vue:31:10 - error TS2345: Argument of type '{}' is not assignable to parameter of type 'NonNullable<(Readonly<{ [K in keyof T as `header-${K & string}`]: () => unknown; } & { [K in keyof T as `cell-${K & string}`]: (props: { value: T[K]; item: T; }) => unknown; } & { "header-__action": () => unknown; "cell-__action": (props: { item: T; }) => unknown; }> & { [K in keyof T as `header-${K & string}`]: () ...'.
31 <slot v-if="$slots[`header-${column}`]" :name="`header-${column}`"></slot>
~~~~
src/components/GenericTable.vue:35:10 - error TS2345: Argument of type '{}' is not assignable to parameter of type 'NonNullable<({ [K in keyof T as `header-${K & string}`]: () => unknown; } & { [K in ke
yof T as `cell-${K & string}`]: (props: { value: T[K]; item: T; }) => unknown; } & { "header-__action": () => unknown; "cell-__action": (props: { item: T; }) => unknown; })["header-__action"] & (() => unknown)> extends (props: infe...'.
35 <slot v-if="$slots['header-__action']" name="header-__action"></slot>
~~~~
src/components/GenericTable.vue:43:10 - error TS2345: Argument of type '{ value: T[keyof T & string]; item: T; }' is not assignable to parameter of type 'NonNullable<(Readonly<{ [K in keyof T as `header
-${K & string}`]: () => unknown; } & { [K in keyof T as `cell-${K & string}`]: (props: { value: T[K]; item: T; }) => unknown; } & { "header-__action": () => unknown; "cell-__action": (props: { item: T; }) => unknown; }> & { [K in keyof T as `header-${K & string}`]: () ...'.
43 <slot v-if="$slots[`cell-${column}`]" :name="`cell-${column}`" :value="row[column]"
~~~~
src/components/GenericTable.vue:50:10 - error TS2345: Argument of type '{ item: T; }' is not assignable to parameter of type 'NonNullable<({ [K in keyof T as `header-${K & string}`]: () => unknown; } & { [K in keyof T as `cell-${K & string}`]: (props: { value: T[K]; item: T; }) => unknown; } & { "header-__action": () => unknown; "cell-__action": (props: { item: T; }) => unknown; })["cell-__action"] & ((props: { ...; }) => unknown)> extends...'.
50 <slot name="cell-__action" :item="row as T"></slot>
~~~~
Found 4 errors.
ERROR: "type-check" exited with 2.
Link to minimal reproduction
https://github.com/PierreSchwang/vue-generic-slots-reproduction
Any additional comments?
It previously worked for me and just occurred after updating vue-tsc. I could pinpoint it breaking when updating from 2.2.2 to 2.2.4.
Not even sure if the issue is even fitting into this repository or if it is because of an updated (peer-)dependency.