初めに
本業で、携わっているサービスはフロントをNuxt × TypeScriptで書いていたのですが、
直近でReactに乗せ換える話が出てきました
乗せ換え作業はおそらく私がほぼ一人で進めることになると思っているのですが、
その際に、なぜReact化する化をCTO含めチーム全体に説明する必要があるので
その理由の一つであるPropsの型定義の曖昧差について書いていきます
propsの型検査について
参照
プロパティを用いた子コンポーネントへのデータの受け渡し
型検査について
propsはいくつかの、組込みで型指定をすることができます
props: {
hoge: String
}
また、ユーザー定義についてはPropType
で型推論することができます
props: { hoge: { type: Object as Vue.PropType<THoge> } }
上記の設定により、propsを受け取るComponent内では型を持ったpropsを使用することができます
また、親Componentから値を渡す際に、異なる型の値を渡すとエラーが確認できます
propsの型の曖昧さについて
上記のように型を定義することができればpropsを利用するComponent内では
TypeScriptの型のアシストを受けて実装するとができます
しかし、propsに対する型定義は厳密とは言えず
割となんでもやることができます、
なぜなら、親Componentでは子Componentでの定義を知らないので
v-bindまたは、v-modelにはどのような型のプロパティでも渡すことができてしまいます
例えば、下記の例では子ComponentではTHoge
というObjectが渡されることを期待していますが、
親Componentではstring型を渡しています
この場合、Consoleにエラーが出力するものの、コンパイルエラーではないので騙せてしまいます
子Component
import Vue from 'vue' type THoge = { hoge: string, hogehoge: number } export default Vue.extend({ name: 'NuxtTutorial', props: { hoge: Object as Vue.PropType<THoge> }, methods: { getHoge(): THoge { return this.hoge } } }) </script>
親Component
export default Vue.extend({ name: 'IndexPage', components: { Tutorial }, data(){ return { hoge: hoge: "hoge" } } })
Vue DevToolでporpsの中身を確認してもstringで渡せていることが確認できます
これを回避するために、普段は子Componentで定義したtypeを親で読み込んで定義することで propsとして意図しない型を渡すことを防いでいます
子Component
import Vue from 'vue' // typeもexport export type THoge = { hoge: string, hogehoge: number } export default Vue.extend({ name: 'NuxtTutorial', props: { hoge: Object as Vue.PropType<THoge> }, methods: { getHoge(): THoge { return this.hoge } } }) </script>
親Component
import Vue from 'vue' // Vueとともにtypeもimport import Tutorial, { THoge } from "~/components/Tutorial.vue" type DataType = { hoge: THoge } export default Vue.extend({ name: 'IndexPage', components: { Tutorial }, data(): DataType { return { hoge: { hoge: "hoge", hogehoge: 1 } } } })
とはいえ、この方法は親Componentでも同じ型定義をしているだけであって
やはり、propsに対する型定義をは言えないのが現状です
最後に
propsへの型定義が曖昧であることはVueをやめてReactに理由の一つにすぎません
Vueがつらいと感じるのは大体TypeScriptとの相性の悪さに起因することが多く、TypeScriptとの相性の悪さをとても実感しました
とはいえ、現在サービスがNuxtで構築したことについては後悔はなく、
特にtemplateベースでかけるのは非常に書きやすかったです
(おそらく、Reactだったらリリースに間に合っていなかった)