【TypeScript】typeofとkeyofでもう迷いたくない
はじめに
TypeScriptでよく使う typeof
と keyof
の使い分けにいつも悩んでしまうので、備忘録としてここにまとめておくことにしました。
typeof
で型を取得する
1. typeof
は、JavaScriptの値の型を取得するものとしてよく知られていますが、TypeScriptでは「ある変数の型そのもの」を取り出すために使えます。
使い方
const userName = "shige";
type UserNameType = typeof userName; // string 型
上の例では、 userName
変数の型である string
を UserNameType
に代入しています。これにより、型を明示的に書かずにすむため、コードの保守性が上がります。
活用例:オブジェクトの型を再利用する
オブジェクトの型を定義するときも typeof
は便利です。
const user = {
name: "shige",
age: 25
};
type UserType = typeof user;
これで、UserType
は{ name: string; age: number; }
というオブジェクト型になります。複雑なオブジェクトの型も一度定義すれば再利用しやすくなります。
keyof
でオブジェクトのキーを型として取得する
2. keyof
を使うと、オブジェクトのプロパティ名を「型」として取得できます。つまり、オブジェクトのキーに注目して、限定された型を作るのに役立ちます。
使い方
type User = {
name: string;
age: number;
};
type UserKeys = keyof User; // "name" | "age"
この例では、UserKeys
が"name" | "age"
というString Literal Union Typesになります。これによって、User
型のプロパティにアクセスできるキーだけを許可したいときに役立ちます。
活用例:キーに基づいた型の制約を作る
たとえば、オブジェクトのプロパティ名に基づいた関数を作ることも可能です。
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = {
name: "shige",
age: 25,
};
const userName = getProperty(user, "name"); // OK
const userAge = getProperty(user, "age"); // OK
ここで、key
はuser
オブジェクトのプロパティ名("name"
か "age"
)でなければならないという制約がかかります。キーに基づいた型安全なコードが書けるので、エラーの発生を防ぐことができます。
3. おまけ
これまでのtypeof
とkeyof
を組み合わせた使い方もあります。
const user = {
name: "shige",
age: 25
};
type UserKeys = keyof typeof user; // UserKeysは "name" | "age" になります
上記はtypeof
を使わないとuser
変数から直接型情報を取得することができないため、keyof
単独で使用することはできません。
なので、typeof
で変数から型情報を取得し、その型に対してkeyof
を使ってキーの型を得ることで、オブジェクトのプロパティ名を利用できるようになります。
参考文献
Discussion