追記
2019/6/24
そもそも公式に説明があったのを見逃していた
https://vuefire.vuejs.org/vuexfire/binding-subscriptions.html#using-the-data-bound-by-vuexfire
概要
公式ドキュメントを見ながらvuexfireの導入を進めていたときのこと、「doc.data()を同期してstateに持っててくれるのか、これは便利だ・・・。ん、でもdoc.idはどこいった?updateとかdeleteはどう実装するんだ?あれれれれ」と軽くハマったが、これを通してObjectのpropertyには列挙可能なやつとそうじゃないやつがあるということを知った、という話。
ハマった流れ
typescriptの練習としてTODOアプリを作っていたときのことでした。
1.vuexfireの導入
npm install vuexfire
2.firestoreをbind
https://vuefire.vuejs.org/vuexfire/binding-subscriptions.html#binding-in-actions
公式ドキュメントを見ながら書いただけ
3.vueで表示
vue-devtoolsでstateを確認、ちゃんと取れてそう。
v-for使って中身を取ってきた配列データを表示してみたところ、問題なさそう。わお!便利!
4.createを実装する。
vuexfireは片方向に同期してくれるだけなので、追加や変更などは通常通り実装する必要があります。
まずはcreateを実装してみたところ、問題無くできた。ちゃんと同期されてる!楽チンで嬉しい!
5.updateを実装する。
ref.doc(id).set({ payload }, { merge: true })
という感じでfirestore上の上書きしよう。
・・・あれ、id無くね?
ここでハマりました。
vue-devtoolsで中身を見ても、idが見当たらないのです。うーん・・・。

本題
console.log()してみる
知り合いが先に取り組んでいたので相談してみたところ、「普通にid使えるはずです・・・。ちょっとconsoleに出してみてください。」とのこと。
なるほど・・・?
ではやってみましょう。(chromeです)
ありましたありました。vue-devtoolsには見えてないだけで、普通にありました。
idプロパティの色が薄いのが気になりますが、ありましたね。
なので、普通にtodo.id
みたいな感じでアクセスすれば使えました。
なんだか狐につままれたような気分です。vue-devtoolsに出ないということは取れて無いと思っていたが、どうやらそうではないらしい。
vuexfireのソースコードを読んでみる
落ち着いてvuexfireのidを扱っている辺りのソースコードを読んでみます。
該当部分がここです。doc.data()とdoc.idをくっつけたオブジェクトを返す関数が定義されています。
function createSnapshot (doc) {
// defaults everything to false, so no need to set
return Object.defineProperty(doc.data(), 'id', {
value: doc.id
})
}
"Object.defineProperty()"というところがとても怪しい。
mozillaのドキュメントを確認してみよう。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
これによると、Objectの持つプロパティについて、細かく設定が出来るとある。
プロパティの追加と言ったら
let obj = {
a: 1,
b: 'hoge'
}
obj.c = 'added'
みたいな書き方しか知らなかったが、上位互換みたいなやつがあるっぽい。
これを参照しながらvuexfireのコードを読み解くと、doc.data()のオブジェクトに対して"id"プロパティを追加する際、
{
enumerable: false,
writable: false,
configurable: false,
value: doc.id
}
というオプションにが設定されるっぽい(デフォルト値についても明示的に書いてます)。
この中だとenumerableオプションが怪しいので、また調べる。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
列挙可能な (enumerable)プロパティとは、内部の [[Enumerable]] フラグがtrueに設定されているものであり、単純な代入や初期化で生成されたプロパティはデフォルトでそうなります(一方、Object.defineProperty()で追加したプロパティはデフォルトで [[Enumerable]] が false になります)。 列挙可能なプロパティは、名前がSymbolである場合を除いて、 for...in ループの対象になります。
なるほど!enumerableオプションがfalseだとプロパティ列挙しようとしても出てこないと。(consoleで薄い色だったのもそのせい?)
vuexfireでenumerable: false
としているのは、なるべく元のデータ構造を壊さないようにという考えでしょうか?
(追記)公式ドキュメントにそんなような事が書いてありました。
ちなみに、idはvue-devtoolsに出てこなかったわけですが、template内で{{todo}}
のようにマスタッシュ記法で表示させようとしても、スプレッド演算子で展開するときもやはり出てきません。