LoginSignup
0
0

More than 3 years have passed since last update.

型でも実装でも使えるサブセットレコードのフィールド一覧

Posted at

ある型のレコードを格納しているデータベースから、その一部のフィールドだけに絞って取得したときの型。例えばこんな感じのことをするとき。

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 で実装から型へ変換して、keyofid: 1 のうちキー 'id' を得ます。加えて Pick のタイミングで fields の内容が User の一部であることも確認できて良い感じです。

めでたい。

で、ここから未解決ゾーンです。

まあ動いてるんですが、不満なのは対象のフィールドをオブジェクトで持っている点。たまたま MongoDB 的には 1 が意味を持つのでそれはそれで良いんですけど、これを文字列の配列みたいなのにできないでしょうか。

こんな感じで。

const fields = [
  'id',
  'name',
] as const;

ここから文字列を抜き出して union type 作って Pick に与えるのができなかった。infer なんかでどうにかならないですかね。ちなみに一度オブジェクトで作ってから配列化、みたいなのはあんまりやりたくないです。

誰か教えてください。

0
0
2

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
0
0