Vue
の Boolean
の プロパティのデフォルト値を省略した場合の挙動についてのメモです。
調べたVue
のバージョンは 3.0.11
です。
検証コード
<template>
<ChildComponent />
</template>
<script lang="ts">
import { defineComponent } from "vue";
import ChildComponent from "./ChildComponent.vue";
export default defineComponent({
name: "ParentComponent",
components: {
ChildComponent,
},
setup() {
return {};
},
});
</script>
<template>
<div></div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "ChildComponent",
props: {
testValue: {
type: Boolean,
},
},
setup(props) {
console.log(props.testValue); //false が出力される
return {};
},
});
</script>
testValue
という Boolean
型のプロパティを定義してデフォルト値をなしにしています。
この時にtestValue
を console.log
で出力してみました。
default
がないので undefined
になるかと思ったのですが false
になるようです。
Vueのコードを追いかけてみる
componentProps.ts あたりでされているようです。
resolvePropValue
という関数の この部分を見てみます。
// boolean casting
if (opt[BooleanFlags.shouldCast]) {
if (!hasOwn(props, key) && !hasDefault) {
value = false
} else if (
opt[BooleanFlags.shouldCastTrue] &&
(value === '' || value === hyphenate(key))
) {
value = true
}
}
ここのコードにより value=false
が行われているようです。
BooleanFlags.shouldCast
, BooleanFlags.shouldCastTrue
を参照しているようですがこれは
const enum BooleanFlags {
shouldCast,
shouldCastTrue
}
このように定義されています。
props
の各プロパティに追加する属性として定義されているような感じ(かな?)
hyphenate
はAbcDef
をabc-def
という値に変換する関数です。
opt
に対する設定は normalizePropsOptions
という関数のこの部分で行われています。
(こっちの関数だとprop
ですね)
const opt = raw[key]
const prop: NormalizedProp = (normalized[normalizedKey] =
isArray(opt) || isFunction(opt) ? { type: opt } : opt)
if (prop) {
const booleanIndex = getTypeIndex(Boolean, prop.type)
const stringIndex = getTypeIndex(String, prop.type)
prop[BooleanFlags.shouldCast] = booleanIndex > -1
prop[BooleanFlags.shouldCastTrue] =
stringIndex < 0 || booleanIndex < stringIndex
// if the prop needs boolean casting or default value
if (booleanIndex > -1 || hasOwn(prop, 'default')) {
needCastKeys.push(normalizedKey)
}
}
プロパティのtype
の中にBoolean
が含まれていたら BooleanFlags.shouldCast
のところはtrue
になるようです。
また プロパティがBoolean
のみ もしくは 複数の型を許容しておりBoolean
, String
の順番で登録されていると BooleanFlags.shouldCastTrue
が true
になるようです。
上記の内容を踏まえたうえで、追加の検証をしてみる
上記のコードを確認したうえで 追加の検証をしてみます。
<template>
<ChildComponent
boolean02
booleanOrString02
booleanOrString04
hyphenate01="hyphenate01"
hyphenate02="hyphenate02"
/>
</template>
<script>
部分は省略
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "ChildComponent",
props: {
//Booleanのみ
boolean01: {
type: Boolean,
},
boolean02: {
type: Boolean,
},
//Booleanが先
booleanOrString01: {
type: [Boolean, String],
},
booleanOrString02: {
type: [Boolean, String],
},
//Stringが先
booleanOrString03: {
type: [String, Boolean],
},
booleanOrString04: {
type: [String, Boolean],
},
//特殊
hyphenate01: {
type: [Boolean, String],
},
hyphenate02: {
type: [String, Boolean],
},
},
setup(props) {
console.log(props.boolean01); //false
console.log(props.boolean02); //true
console.log(props.booleanOrString01); //false
console.log(props.booleanOrString02); //true
console.log(props.booleanOrString03); //false
console.log(props.booleanOrString04); //(空文字列)
console.log(props.hyphenate01); //true
console.log(props.hyphenate02); //hyphenate02
return {};
},
});
</script>
<template>
部分は省略
上記のような結果になりました。
String
, Boolean
の順番を入れ替えると props名のみを与えた場合の挙動は異なるようです。
hyphenate01
がtrue
になることは意外でした。
感想
ただのBoolean
のプロパティについてでしたが コードを見てみると意外な発見があり面白かったです。