ある型のレコードを格納しているデータベースから、その一部のフィールドだけに絞って取得したときの型。例えばこんな感じのことをするとき。
SELECT id, name FROM users
ここでいう id, name
をどう持つかという話です。
サブセットを抜き出すのは Pick
という utility type を使ってやれます。
やれるんだけど、必要なフィールドの一覧は型だけじゃなくて実装の方でもクエリに乗せるとかで使うじゃないですか。同じものを2度書くのは不具合の素なので、実装コードから取ってきて型へ反映させるようにしたいですね。
そんなわけで、こんな感じでやれます。
import mongodb from 'mongodb';
const db: mongodb.Db;
// 元のレコード
type User = {
id: number;
name: string;
email: string;
imageUrl: string;
}
// 抜き出すフィールドの一覧
// (これを型でも実装でも使う)
const fields = Object.freez({
id: 1,
name: 1,
});
// サブセット
type UserListItem = Pick<User, keyof typeof fields>
// 結果 => {
// id: number;
// name: string;
// }
// 取る
const coll = db.collection<User>('users');
const query = {};
const users = await coll.find<UserListItem>(query, fields).toArray();
// 取れたぜ
users.forEach((user) => {
console.log('User', user); // { id, name }
});
typeof
で実装から型へ変換して、keyof
で id: 1
のうちキー 'id'
を得ます。加えて Pick
のタイミングで fields
の内容が User
の一部であることも確認できて良い感じです。
めでたい。
で、ここから未解決ゾーンです。
まあ動いてるんですが、不満なのは対象のフィールドをオブジェクトで持っている点。たまたま MongoDB 的には 1
が意味を持つのでそれはそれで良いんですけど、これを文字列の配列みたいなのにできないでしょうか。
こんな感じで。
const fields = [
'id',
'name',
] as const;
ここから文字列を抜き出して union type 作って Pick
に与えるのができなかった。infer
なんかでどうにかならないですかね。ちなみに一度オブジェクトで作ってから配列化、みたいなのはあんまりやりたくないです。
誰か教えてください。