配列型 T[] から T だけ取り出して使う方法

以下はちゃんと管理されているプロジェクトでは、こんなことはあまり起こらないだろうなという内容です。

僕は Flux の State 部分をこのように定義して使ったりすることが多いです。

interface State {
  values: {foo: any; bar: any}[];
}

オブジェクト部分なども直で書いてます。(APIの仕様がはっきりしないままで、どの値を使えばいいのか曖昧なことが多いというのが大きい、今の会社)

そして、例えばそのvaluesのうちの1つ、つまり{foo: any; bar: any}だけを受け取る関数などを定義したいときに、指定に例えば(value: {foo: any; bar: any}) => voidのようにしても問題はあまりないですが、できれば先程定義したStateから使いたいです。

TypeScript の型は子プロパティ名で絞り込んでいくことができます。つまり、{foo: any; bar: any}[]State['values']とも書くことができます。ただここで「[]はどうすれば取り払えるんだろう」と頭をひねりました。ただそれはすぐ解決することができました。

配列型 T[] から T だけ取り出して使う

ここでいうT[]ですが、実は TypeScript では以下のように定義したものとほぼ同じです。

interface StateValues extends Array<string> {
  [n: number]: string
}

const state: StateValues = ['foo'];

この[n: number]: string部分はインデックス署名と言い、extends numberなプロパティ名ならプロパティへのアクセスが許可されるようになります。これは型のプロパティ名での絞り込みでextends numberな型を指定することで、さらに絞ることができるということになります。

つまり、以下のような絞り込み方法があります。(僕的にはnumberがいいかなと思います)

const value0: State['values'][number] = 'foo';
const value1: State['values'][0] = 'foo';
const value2: State['values'][1] = 'foo';
const value99: State['values'][99] = 'foo';

ちなみに、State['values'][]とするとこれは{foo: any; bar: any}[][]となってしまうので注意です。