Subscribe on changes!

Support passing generic to child components

avatar
Apr 3rd 2023

What problem does this feature solve?

We can pass type parameter in TypeScript via generics:

function <T extends string | number>doSth(value:T): T[] {
  if (value === "123") {
    return toArray(123);  // throw an error, number[] is not compatible with T[]
  }
 return toArray<T>(value)
}

But we cannot do so in Vue template.

<my-select v-model="selectedFruit">
  <my-option value="๐ŸŽ" />
  <my-option value="๐ŸŒ" />
  <my-option value="๐Ÿ˜" /> // should throw an error, ๐Ÿ˜ is not compatible with selectedFruit 
</my-select>

To make this possible, we need the ability to restrict what components can be in slot๏ผš ts defineSlots({ default: { accept: MyOption<T> } }) vue <my-select v-model="selectedFruit"> <my-option value="๐ŸŽ" /> <my-option value="๐ŸŒ" /> <my-option value="๐Ÿ˜" /> // ๐Ÿ˜ is not compatible with selectedFruit </my-select> also, now we have ability to prevent developer from putting unexpected components in slots! vue <my-select v-model="selectedFruit as any"> <my-radio v-model="radioValue" /> // throw an error, my-radio should not be here </my-select>

Sometimes TypeScript cannot infer acutal type we want:

<my-button-group :buttons="['๐Ÿš', '๐Ÿ—']" @click="handleUpdate" />
type Foods = '๐Ÿš' | '๐Ÿ—';
const handleClick= (food: Foods) => {
   console.log(food);
}

buttons will infer as string[], and @click handle is (value: string) => void, but we need Foods[] and (value: Foods) => void So we also need ability to specify what type we want:

<my-button-group[Foods] :buttons="['๐Ÿš', '๐Ÿ—']" @click="handleUpdate" />

What does the proposed API look like?

For template:

<my-select[typeof selectedFruit] v-model="selectedFruit">
   <my-option value="๐ŸŽ" />
   <my-option value="๐ŸŒ" /> 
   <my-option value="๐Ÿ˜" /> // ๐Ÿ˜ is not compatible with selectedFruit 
</my-select>
<my-select v-generics="typeof selectedFruit" v-model="selectedFruit">
   <my-option value="๐ŸŽ" />
   <my-option value="๐ŸŒ" /> 
   <my-option value="๐Ÿ˜" /> // ๐Ÿ˜ is not compatible with selectedFruit 
</my-select>

For slot type definition:

defineSlots({
   default: {
     accept: MyOption<T>
  }
})
avatar
Apr 3rd 2023

This is an issue that requires consideration. In my opinion, using v-generic (in line with <script setup lang="ts" generic="T">) would be preferable. It's not feasible to add generics to the element tag as we need to maintain compatibility with native HTML code.

For slots, see https://github.com/vuejs/core/pull/7982#issuecomment-1493923997


/cc @johnsoncodehk

avatar
Apr 4th 2023

I have same requirements

avatar
Apr 4th 2023

Much needed feature

avatar
May 5th 2023

้™„่ฎฎใ€‚ๅพˆ้œ€่ฆ่ฟ™ไธชๅŠŸ่ƒฝ๏ผŒๅ›ข้˜Ÿไธๆ–นไพฟ็”จjsx Much needed feature

avatar
Feb 3rd 2024

+1 for this