LoginSignup
14
13

More than 5 years have passed since last update.

TypeScript で動的にプロパティを定義するライブラリに型をつける

Posted at

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 にキャストしてやります.親クラスから子インターフェースへの変換ですので,これは安全で問題なくキャストできます.また,インターフェースであってクラスではないので追加のオーバーヘッドも無いはずです.

14
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
13