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"
}
完全ではない
この方法にはいくつかの制限があります。
- ネストされたオブジェクト: ネストされたオブジェクトの場合、型推論が正しく機能しないことがあります。
- 配列の扱い: 配列の場合、キーが数値になるため、意図した型が得られないことがあります。
- 型の変換:
Object.entries()
の返り値を別の型に変換する際に、型安全が失われる可能性があります。
とはいえ、通常の型定義よりは厳格に型を扱えるようになるため、状況に応じて使い分けると良いでしょう。