Vue.js has a feature called name slots which can be used to override whatever gets rendered by default for a certain slot:
<td v-for="(column, index) in tuple">
<slot
:name="slotName(column)" // string
:value="getValue(item, column) as TupleValues<typeof tuple, typeof item>[index]
This is how it gets used:
<template #score="{ value }">
// value should be TupleMap<typeof tuple, typeof item>['score']
// score is the slot name previously returned by slotName(column)
</template>
This is a pattern used to customize whatever gets rendered by default for a certain slot.
columns is a tuple which defines each column of the table and which key should be used to get their value from the items of an array (the tuple can also define a function that returns a custom value for the column). Each item of the array represents a row.
I can easily get the value type from each tuple element with these types:
type TupleValues<
T extends Array<{ key: keyof U | string; value?: keyof U | string | ((...args: any[]) => any) }>,
U
> = {
[P in keyof T]: T[P]['key'] extends keyof U
? U[T[P]['key']]
: T[P]['value'] extends keyof U
? U[T[P]['value']]
: T[P]['value'] extends (...args: unknown[]) => unknown
? ReturnType<T[P]['value']>
: never
}
and
type TupleMap<
T extends Array<{ key: keyof U | string; value?: keyof U | string | ((...args: any[]) => any) }>,
U
> = {
[P in T[number] as P['key']]: P['key'] extends keyof U
? U[P['key']]
: P['value'] extends keyof U
? U[P['value']]
: P['value'] extends (...args: unknown[]) => unknown
? ReturnType<P['value']>
: never
}
But unfortunately the v-for loop makes it pointless.
Instead of using v-for I could manually define a slot for each tuple index, but that won't scale to any arbitrary column number:
<td>
<slot
:name="columnName(columns[0])" // I can infer the exact slot name from the tuple
:value="getValue(item, column) as TupleValues<typeof tuple, typeof item>[0] // I can infer the exact slot value form the tuple
> <DefaultSlotRenderer /> </slot>
</td>
<td>
<slot
:name="columnName(columns[1])" // I can infer the exact slot name from the tuple
:value="getValue(item, column) as TupleValues<typeof tuple, typeof item>[1] // I can infer the exact slot value form the tuple
> <DefaultSlotRenderer /> </slot>
</td>
<td>
<slot
:name="columnName(columns[2])" // I can infer the exact slot name from the tuple
:value="getValue(item, column) as TupleValues<typeof tuple, typeof item>[2] // I can infer the exact slot value form the tuple
> <DefaultSlotRenderer /> </slot>
</td>
EDIT: turns out it doesn't work even without the v-for loop and it's not the typings fault.
You should copy paste it locally because playground's intellisense is not the best.
The answer was defineSlots