-
Notifications
You must be signed in to change notification settings - Fork 547
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
Typed slots #192
base: master
Are you sure you want to change the base?
Typed slots #192
Conversation
Wouldn't it be better to add it to |
I think it would be better to have automated tools to generate EDIT: this would also allow us to check at runtime if the user is trying to use a slot that doesn't exist. |
How would you type slots that depend on props? |
You would need to type it the same as props (duplicating it). |
If this is primarily a TypeScript type hinting wouldn't it be better to export slot typing separately? <script lang="ts">
export type slots = { default: { message: string } }
...
</script> |
👍for typed slots but I am not a fan of having an extra option that will bloat my production build unless it will be possible to remove these declarations by babel plugin? |
Needs to work with
I'm thinking doing something similar to typed |
But how these typings are going to be useful outside of SFC? I thought that the main idea was to provide type hints inside of Also, what prevents template compiler from doing just that? It knows for sure which slots are available from a component, the only thing missing is prop types, but I guess it is doable as well? <slot :foo="foo as string" /> Related issue: vuejs/core#1359 |
Better typing will be useful everywhere where we need to use the slots, this will be on the component who describes the export default defineComponent({
slots: {
top: null, // no value
item: Object as () => { item: { value: number }; i: number },
},
setup(_, { slots }) {
const items = Array.from({ length: 10 }).map((_, value) => ({ value }))
return () => {
return h('div', [
//slots.top({a: 1}), // type error no args expected
//slots.random({a: 1}), // type error no slot defined
slots.top(),
items.map((item, i) => h('div', slots.item && slots.item({ item, i }))),
])
}
},
})
The motivation is better Typescript support! That's not only on the template but anywhere we will use component.
Render function support.
I don't believe this has anything to do with that, this RFC is providing types only for slots, that is to provide typescript support on the template. |
I don't suppose there's a way to solve: export default defineComponent({
setup(props, { slots }) {
return () => {
return h('div', [
props.items.map(item => slots[item.name] && slots[item.name]({ item })),
// or
props.items.map(item => slots[`${item.name}-cell`] && slots[`${item.name}-cell`]({ item })),
])
}
},
}) where slots are dynamic? |
You can't describe that with typescript :/ |
I was support slot type check by IDE with no additional options: https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar But for third party library like So if have a slots option let typescript can emit the slots types to |
Vue 3 already has Vue has And about dynamic slot names. This issue is the same as Dynamic event names in emits option. So, it seems slots are a part of component interface similar to emits with similar problems, and it would be great to have all defined. |
It makes sense to make components more type-safe by statically typing their slots interface. Just want to point out that as is it creates more TS confusion. More generally that's not great DX and should fall in the same umbrella as the discussion you started in #282 for props. So I 👍 the concept/idea but the fine API details could need some TS love. |
Naming wise they are different,
That's optional API, probably could be used to make sure the parameter passed to the That's a optional API, similar to defineComponent({
slots: {} as {
test: null
item: { item: { value: number }; i: number }
},
setup(_, { slots }) {
slots.test!()
slots.item!({
i: 22,
item: {
value: 22
}
})
}
}) Also other API that could be possible would be a similar to the defineComponent({
slots: {
test(){
},
item(item: {value: number}) {
}
}
}) But the slot can only take one parameter, which will probably confuse some users, and the execution of the function would not be used (besides runtime validation - already mentioned above).
That RFC is unrelated to this one.
If you have more feedback, please let me know. |
I agree, but if they're similar then they should have similar API. For example call it Or do you plan on back-porting that new syntax to type
That would be
It probably doesn't make that much sense because the component defines the slot and provides it -- as opposed to props where the component defines the props and users provides values. The same could be said of the
That's nice! I suppose
Not directly, but I feel like we should have a unified, easy way to do all the typings in TS, which is a bit what #282 is about (I think?) albeit focused on props.
Now that you've shown me that A random thought I had while thinking about those things: do you think It's just a random idea, I haven't thought this through. |
Still need to think about it,
I have the same opinion, I can see it be useful and be useless, I guess that can leave that to the developers, like we do on the
It won't work because of Typescript,. you would need to cast something to your expected type/interface.
I would like to keep the scope of each RFC as small as possible,
There's no concise way yet to describe a lot of things, each IDE/PLUGIN has it's own way to declare types, hopefully this RFC will allow us to describe more component related types on the component through typescript. My goal is: You should be allowed to describe all the necessary things on the component, such as
Yep, you should be able to do that already, but that's the goal. |
This probably isn't possible with the current API but generic slot types would also be useful, for example if I have a component that iterates over an array passed to its defineComponent(<T extends any>() => ({ // I think this is already used to pass a setup function directly
props: {
items: Array as PropType<T[]>
},
slots: null as {
item: SlotType<{ item: T }>
},
setup (props, { slots }) {
return () => (
<ul>{
props.items.map(item => (
<li>{ slots.item({ item }) }</li>
))
}</ul>
)
}
})) Then using it could be completely safe: <my-list :items="items">
<template #item="{ item }">
{{ item.bar }} <!-- Property 'bar' does not exist on type '{ foo: string; }' -->
</template>
</my-list>
<script>
export default {
data: () => ({
items: [{ foo: '' }]
})
}
</script> |
@KaelWD that's a timely comment! Recently I've been trying Volar that typechecks your templates and I had a lot of issues similar to your example. When I have a bit of time I'm gonna open a discussion in vue-rfcs to argue that we need generic components. Slots is one part of it, but even simple props need it, otherwise you get lots of errors in non-basic scenarios. It's gonna be challenging but I believe it's the only way if we want type-safe templates. |
Oh yeah definitely, we have stuff like this too: defineComponent(<T extends object>() => ({
props: {
items: Array as PropType<T[]>,
itemKey: String as PropType<keyof T>
}
})) |
I want to defineComponent like this: defineComponent<
<T, T1, T2>() =>
| {
$props: {
value: T
foo: T1
bar: T2
titleRenderProp: (value?: T) => VNode
}
$emit: {
(event: 'update:value', value: T): void
}
}
| {
$props: {
value: T
foo: [T1]
bar: [T1, T2]
}
$emit: {
(event: 'update:value', value: T): void
}
$slots: {
title: (slotProps: { value?: T }) => VNode[] | undefined
}
}
>({
props: ['value'],
setup() {}
}) Because the types of |
It's very helpful to me! |
Will this ever be solved? Makes TS almost useless in large Vue3 projects, especially when one is writing a lot of reusable/library code. Generic components and typed slots are must IMO. |
I just add the So I implement this feature. With it, it's possible to declare slot type in Basic Example<script setup lang="ts">
defineSlots<{
// slot name
title: {
// scoped slot
foo: 'bar' | boolean
}
}>()
</script> |
It would be so great to have this finalized! |
Allow to describe
slots
andtypes
SFC
Render
Type only
Rendered