Skip to content

Support passing generic to child components  #8015

Closed
vuejs/language-tools
#4971
@KawaiiZapic

Description

@KawaiiZapic

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:

defineSlots({
   default: {
     accept: MyOption<T>
  }
})
<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!

<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>
  }
})

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions