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