Vue で空文字が Prop で渡ってきてバグってしまった話
はじめに
数年前に作られていた vue 2 (TypeScript なし) のプロダクトで空文字が Prop で渡ってきてバグってしまった話と、注意点を備忘録として残します。
背景
数年前に作られていた vue 2 (TypeScript なし) のプロダクトで下記のようなコンポーネントがありました。
export default {
props: {
sample: Boolean,
default: false,
},
};
このコンポーネントはこのように呼び出されています。
<template>
<Sample :sample="sample2" />
</template>
この sample2、実は文字列が入っていました!
設計者の意図としては、JS の暗黙的な型変換と同様に空文字列であれば false、 1 文字以上であれば true という実装にしたかったのだと考えられます。
空文字列 "" が true !?
ある日、 sample2 に空文字列 "" が入ってきました。しかし、 Sample が false の場合の挙動をしません。
なんと、 空文字 "" が入ってきたときにコンポーネント内で false に変換されていたのです。
空文字 "" は JavaScript の真偽判定において Falsy になるのでしばらく原因を理解するのに時間かかりました。
Falsy (偽値) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
https://developer.mozilla.org/ja/docs/Glossary/Falsy
原因は、v-bind において、 falsy な値は null, undefined, false だけという仕様があるためです。
Migration from Vue 1.x — Vue.js
https://v2.vuejs.org/v2/guide/migration.html#Truthiness-Falsiness-with-v-bind-changed
なぜ
HTML Attribute と同じ挙動になるように揃えたみたいです。個人的には React (JSX) と同じ挙動なのでわかりやすく感じます。 v-if などは引き続き JavaScript の真偽判定と同様の挙動をするようです。
まとめ
- そもそも boolean な prop に文字列を渡さないようにしよう
- このようなプログラムを書かれないように規約を設けるという意味でも TypeScript は必須ですね