vuejs / language-tools

⚡ High-performance Vue language tooling based-on Volar.js
https://marketplace.visualstudio.com/items?itemName=Vue.volar
MIT License
5.6k stars 375 forks source link

Dynamic slots error with generics #4538

Open csisy opened 3 days ago

csisy commented 3 days ago

Vue - Official extension or vue-tsc version

2.0.26

VSCode version

1.91.0

Vue version

3.4.31

TypeScript version

5.5.3

System Info

No response

Steps to reproduce

Trying to build a table component which has a single generic parameter, representing the type of the data row. Column definitions are given according to this type.

<script setup lang="ts" generic="T extends { [K in keyof T]: T[K] } & { id: PropertyKey }">

// definition of a column
export type ColumnDef<T> = {
  // the property is a key of the generic type
  property: keyof T & string;
  title: string;
};

I'd like to define the slot names and the corresponding props:

// this is the type of the column template; receives the given row and the value based on the given 'property' of the column def.
type ColumnTemplateData<K extends keyof T> = {
  row: T;
  value: T[K];
};

// we will have slots in the `column-{keyof T}` format with these props
defineSlots<{
  [K in keyof T as `column-${K & string}`]: (_: ColumnTemplateData<K>) => any;
}>();

Try to define a slot with a generated name:

<div v-for="col in columns" :key="col.property">
  <!-- error: Type '`column-${UnwrapRef<keyof T & string>}`' cannot be used to index type [...] -->
  <slot :name="`column-${col.property}`" :row="row" :value="row[col.property]">
    <span>{{ row[col.property] }}</span>
  </slot>
</div>

What is expected?

Based on other threads and PR #8374, this should report no errors.

What is actually happening?

When the slot is defined an error is generated:

Type '`column-${UnwrapRef<keyof T & string>}`' cannot be used to index type 'Readonly<{ [K in keyof T as `column-${K & string}`]: (_: ColumnTemplateData<K>) => any; }> & { [K in keyof T as `column-${K & string}`]: (_: ColumnTemplateData<K>) => any; }'.ts-plugin(2536)

Link to minimal reproduction

https://github.com/csisy/vue-dynamic-slots-repro

Any additional comments?

If you try the example (npm run dev), you can see that it actually works runtime.

csisy commented 3 days ago

Might be related? #3787