Open9
vue3 で emit に型をつける方法を調べる
前提として例えば、下記のような親子コンポーネントがあった場合、親の doSomething
関数の引数 count
が number 型 として返ってきて欲しい。
Parent.vue
<template>
<div>
<Child @updateCount="doSomething" />
</div>
<template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
components: {
Child: ()=> import('./Child.vue')
},
setup(_, { emit }) {
return {
const text = ref<string>('MyText')
doSomething: (count)=> {
text.value = count // 怒られてほしい
}
}
}
})
</script>
Child.vue
<template>
<button @click="incrementCount" />
<template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup(_, { emit }) {
const count = ref<number>(0)
return {
incrementCount: ()=> {
count.value++
emit('updateCount', count.value)
}
}
}
})
</script>
※ 親コンポーネントで count を管理したほうがいいのでは?など設計の話は一旦無視する
validator関数 をつかえば、聞くらしい
Vue3ならVolar(Vue Language Features)によるサポートがあります(Veturだと無理)
https://github.com/johnsoncodehk/volar
emits プロパティに記述したvalidator関数((payload) => validate)の引数型が親に伝わる
おそらくこれなんだ思うんだけど
app.component('custom-form', {
emits: {
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
})
これで効くのようになると思ったけど効かぬ。
Child.vue
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
emits: {
updateCount: (count: number) => {
return typeof count === 'number'
}
},
setup(_, { emit }) {
const count = ref<number>(0)
return {
incrementCount: ()=> {
count.value++
emit('updateCount', count.value)
}
}
}
})
</script>
このruntime error だったので vetur オフにしないといけないのかな?と思ったけど、vetur オフにしても補完効かず、ts のほうのエラーは残る。
Parent.vue
doSomething: (count)=> {
text.value = count // 怒られてほしい
}
Parameter 'count' implicitly has an 'any' type.Vetur(7006)
Parameter 'count' implicitly has an 'any' type.ts(7006)
もちろん number つければエラーなくなるが意味ない。
Parent.vue
doSomething: (count: number)=> {
text.value = count
}
この記事見てもこれで問題なさそうだけどなぁ。
上記サイト、親コンポーネントについては書いてないので、emit 発火だけの話?
const onClick = () => {
emit("update", 100)
// emit("hoge") これはエラーになる
// emit("update", "a") 引数の型が一致しないのでこれもエラーになる
}
いや、子コンポーネントで上記のエラーも出ないな。何か初歩的ミスしてそう
公式 の発見したので、ペタ。
const Component = defineComponent({
emits: {
addBook(payload: { bookName: string }) {
// ランタイムバリデーションの実行
return payload.bookName.length > 0
}
},
methods: {
onSubmit() {
this.$emit('addBook', {
bookName: 123 // 型エラー!
})
this.$emit('non-declared-event') // 型エラー!
}
}
})
ん?そもそも setup 関数じゃないけど効くの? vscode の問題な気がしてきた