Ribbit's works

Object.entries()で厳格に型定義された結果を受け取りたい【typescript】

#TypeScript #JavaScript
にメンテナンス済み
記事のトップ画像

typescript の標準設定では、Object.entries()の型は以下のように定義されています。

interface ObjectConstructor {
  entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];
  entries(o: {}): [string, any][];
}

つまり、型をRecord<string, number | string>として定義した値を引数に渡した場合、返り値の型は[string, number | string][]になります。

プロパティがstringの場合
const object: Record<string, number | string> = {
  one: 100,
  two: 'test',
};

const entries = Object.entries(object); // 型は[string, string | number][]

ただ、Record<"one" | "two", number | string>と定義していた場合はどうでしょうか。

通常の方法では、返ってくる型は先ほど同様[string, number | string][]です。

プロパティが"one"|"two"の場合
const object: Record<'one' | 'two', number | string> = {
  one: 100,
  two: 'test',
};

const entries = Object.entries(object); // 型は[string, string | number][]

この時、より厳格に["one" | "two", number | string\][]といった状態で受け取りたいことはありませんか?

今回はこれを実現するコードを紹介します。

ソースコード

type Entries<T> = [keyof T, T[keyof T]][];

Object.entries(object) as Entries<typeof object>;

型推論も問題なく動作します。

type Entries<T> = [keyof T, T[keyof T]][];

const object = {
  one: 100,
  two: 'test',
};

const entries = Object.entries(object) as Entries<typeof object>;

for (const [key, value] of entries) {
  // key: "one" | "two"
}