オブジェクトがリストになっているデータから、オブジェクト内の id をキーにした Map を作成したい時、id の型を interface から取得したかったのメモ
interface
interface Iidol { id: number; name: string; tyep: 'cute' | 'cool' | 'sexy' | 'pop'; }
1. interface のプロパティを直接指定して型を作ることができる
type IdolIdType = Iidol['id']; // => type IdolIdType = number
2. プロパティ名のリテラル型を作成して、それを interface のプロパティとして型を作成
type IdolId = 'id'; type IdolIdType = Iidol[IdolId]; // => type IdolIdType = number
上記の方法で interface から type を作成することができました。
ただ個人的には interface からプロパティの型を取得する必要が出てしまうのであれば、最初からそのプロパティの型を定義しておくほうが見通しが良さそうと感じました。
type IdolIdType = number; interface Iidol { id: IdolIdType; name: string; tyep: 'cute' | 'cool' | 'sexy' | 'pop'; }
IdolId をキーにした Map を作成する
type Idols = Iidol[];
このデータを Map にする
const idols: Iidol[] = [ { id: 1, name: '星宮いちご', type: 'cute'}, { id: 2, name: '霧矢あおい', type: 'cool'}, // ... ]; const getIdoMap = (): ReadonlyMap<IdolIdType, Iidol> => { const map = new Map(); idols.forEach((user) => { map.set(user['id'], user); }); return map; } getIdoMap();
いい感じになりましたが getIdoMap
は idols
が外にあって副作用があるし key が固定なので、もう少し抽象化してみます。
const getMapByKey = <T, K extends keyof T>(data: T[]) => (key: K): ReadonlyMap<T[K], T> => { const map = new Map(); idols.forEach((item) => { map.set(item[key], item); }); return map; }; getMapByKey(idols) => ('id');
API から渡される オブジェクトの入った配列からキーを指定して Map が作れるようになりました!
interafce から型作らなくてもよかった…
所管
interface をオブジェクトのように扱うことでプロパティの型を作成することができる (Interface['property name']
)
ただ特定のプロパティの型が外部で必要であれば別途定義しておくほうが見通しが良い。
特定のプロパティの型が無くても成立する方法がないか考えてみるのが良い。
こんな感じでしょうか。
TypeScript のジェネリクス何となく理解してきました。T
とか K
って何なん?って思っていたのですが、抽象的な型を表すのに伝統的に使われているだけだったと知ってから苦手意識がなくなりました。 ループの i
とか j
みたいなものだったのか〜
[参考]
BADON 新刊出てた!!