4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TypeScriptのObject.keysの型はなぜstringの配列なのか

Last updated at Posted at 2022-11-05

疑問

TypeScriptでObject.keysを使う際keyの型がなぜstringの配列になってしまうのか気になったのでまとめました。

Object.keysでobjectのkey名を取り出したいとき
次のようなコードを書くとkeysの型はstring[]になってしまいます。

const object = {
    hoge: 'hoge',
    fuga: 'fuga',
};
// keysの型は("hoge"|"fuga")[]ではなくstring[]
const keys = Object.keys(object);

よって次のようなコードは型エラーになってしまいます。

// 型エラーになってしまう
const temp = object[keys[0]];

暫定的解決策

これを回避するためには(keyof T)[] を返す関数を作ってそれを利用する。もしくはasを使って型を強制的に決めてしまうことで対処できます。

function getStrictKeys<T extends Record<string, any>>(object: T): (keyof T)[] {
    return Object.keys(object);
}
// keysの型は ("hoge" | "fuga")[]
const keys = getStrictKeys(object);

// 型エラーなし
const temp = object[keys[0]];
// keys[0]の型を無理矢理つける
const temp = object[keys[0] as keyof typeof object];

最初からObject.keysの型を(keyof object)[]にしてくれれば良いのにと思ったのですが

なぜこのような仕様になっているかというと、objectが拡張された時に型安全性が失われてしまうからという理由があるためです。

Object.Keysの型を厳密にすることで発生する問題

具体的には次のような型を考えます

type ObjectType = {
    hoge: string;
    fuga: string;
};

次のような関数を考えます

function printObjectKeys(object: ObjectType) {
    getStrictKeys(object).forEach((key) => {
        // 型補完でkeyの型はhoge|fuga
        if (key !== 'hoge' && key !== 'fuga') {
            throw new Error(`keyがhogeでもfugaでもありません:${key}`);
        }
        console.log(key);
    });
}

この関数はObjectTypeのkeyを出力するだけでkeyの型がhoge|fuga
なので型安全性が保たれていればif文の中には入らないように思えます。

しかし、次のようなObjectTypeを拡張したようなobjectを用意し

const extendObject = {
    hoge: 'hoge',
    fuga: 'fuga',
    piyo: 'piyo',
};

printObjectKeys関数に引数として渡すとなんの静的エラーも出ず実行されてしまいます。
そしてif文の中に入りエラーが発生してしまいます。

// Error: keyがhogeでもfugaでもありません:piyo
printObjectKeys(extendObject);

このようにObject.keysの型を厳格に付けてしまうとかえって静的エラーが出ずtypescriptの良さが失われてしまいます。

所感

Object.keysの型を厳密にする関数の使用やasによる型アサーションはtypescriptの型安全性を失わせる可能性があるのでobjectが拡張される可能性がないと言い切れる時など注意して使う必要があります。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?