ウェブサイト検索

TypeScriptで定数配列のインデックスのユニオン型を作成する方法は?


私は文字列の定数配列を持っています。例えば

const emojis = ['😄', '😊', '😐', '😕', '😣'] as const

そして、私はその配列のインデックスの共用体を含む型を持ちたい、例えば

type emojiIndexes = IndexesOfArray<typeof emojis> // => 0 | 1 | 2 | 3 | 4

そのため、number の使用を許可せず、配列内のインデックスの正確な数だけを使用します

そして、配列のサイズが例えば

// changed from this
// const emojis = ['😄', '😊', '😐', '😕', '😣'] as const
// to this 
const emojis = ['😄', '😊', '😐'] as const // removed 2 emojis

すると、IndexesOfArray<typeof emojis> は 0 | 1 | 2 になります

定数配列のインデックスを持つユニオン型を作成する IndexesOfArray をどのように作成できますか?

回答 #1

こちらが解決策です:(Playgroundリンク)

type TupleIndices<A extends any[]>
    = A extends [any, ...infer T]
    ? TupleIndices<T> | T['length']
    : never

例:

type Foo = ['foo', 'bar', 'baz', 'qux', 'quz']

// 0 | 4 | 3 | 2 | 1
type FooIndices = TupleIndices<Foo>

この解法は再帰的なので、やや長いタプルでは失敗します。もし長いタプルでも動作させたい場合は、末尾再帰版を試すことができます:(Playground リンク)

type TupleIndices<A extends any[], Acc = never>
    = A extends [any, ...infer T]
    ? TupleIndices<T, Acc | T['length']>
    : Acc

使い方は同じです。

回答 #2

これは、空の配列キーをすべてパラメーター型から除外することで行うことができるので、結果としてインデックスだけの共用体になります:

type IndexesOfArray<A> = Exclude<keyof A, keyof []>

const emojis = ['😄', '😊', '😐', '😕', '😣'] as const

type emojiIndexes = IndexesOfArray<typeof emojis> // => '0' | '1' | '2' | '3' | '4'

インデックスは数字ではなく文字列ですが、これは問題を引き起こすべきではありません。もし数字が必要であれば、再帰的な条件付き型を使って生成することもできますが、これによりTypeScriptの再帰の深さに問題が生じます。あるいは、少しハック的なハードコーディングされた配列を使い、それにインデックスを付けて数字を取得することもできます。

type ToNum = [0,1,2,3,4,5,6,7] // add as many as necessary

type emojiNumIndexes = ToNum[IndexesOfArray<typeof emojis>] // => 0 | 1 | 2 | 3 | 4

TypeScript プレイグラウンド

関連記事