Indexed DB の wrapper として Dexie.js を使っています.
Dexie.js では次のようにしてデータベースを生成し,各テーブルにアクセスすることができます. (README.md より)
//
// Declare Database
//
var db = new Dexie("FriendDatabase");
db.version(1).stores({
friends: "++id,name,age"
});
//
// Manipulate and Query Database
//
db.friends.add({name: "Josephine", age: 21}).then(function() {
return db.friends.where("age").below(25).toArray();
}).then(function (youngFriends) {
alert ("My young friends: " + JSON.stringify(youngFriends));
}).catch(function (e) {
alert ("Error: " + e);
});
僕は TypeScript を使って書いているのですが,1点問題があります.Dexie.js では db.friends
のようにテーブルがデータベースオブジェクトのプロパティとして生えてくるのですが,TypeScript のコンパイラはもちろん db.version(1).stores(...)
のスキーマ情報を見てそれを判断してくれません.結果として friends
というプロパティは(静的に)無いよとエラーになります.
こういった動的にプロパティを生やすライブラリは JavaScript ではよくあると思うので,今回行った対処法をメモしておきます.
// スキーマの型を定義
interface Friend {
id: number;
name: string;
age: number;
}
interface TypedDexie extends Dexie {
friends: Dexie.Table<Friend, number>;
}
var db = new Dexie("FriendDatabase") as TypedDexie;
// `.friends` の型が `Dexie.Table<Friend, number>` だと TypeScript のコンパイラは知っているのでエラーにならない
db.friends.where("age").below(25).each(...);
インターフェースがクラスを継承しているのは不思議な感じがするかもしれませんが,これで Dexie
というクラスに friends
というプロパティがあるという追加の情報を付けることができます.
あとは new Dexie
でインスタンスを生成するときにプロパティを付加した型 TypedDexie
にキャストしてやります.親クラスから子インターフェースへの変換ですので,これは安全で問題なくキャストできます.また,インターフェースであってクラスではないので追加のオーバーヘッドも無いはずです.