🫠

【TypeScript】typeofとkeyofでもう迷いたくない

2024/11/13に公開

はじめに

TypeScriptでよく使う typeofkeyof の使い分けにいつも悩んでしまうので、備忘録としてここにまとめておくことにしました。

1. typeof で型を取得する

typeof は、JavaScriptの値の型を取得するものとしてよく知られていますが、TypeScriptでは「ある変数の型そのもの」を取り出すために使えます。

使い方

const userName = "shige";
type UserNameType = typeof userName; // string 型

上の例では、 userName 変数の型である stringUserNameType に代入しています。これにより、型を明示的に書かずにすむため、コードの保守性が上がります。

活用例:オブジェクトの型を再利用する

オブジェクトの型を定義するときも typeof は便利です。

const user = {
  name: "shige",
  age: 25
};
type UserType = typeof user;

これで、UserType{ name: string; age: number; }というオブジェクト型になります。複雑なオブジェクトの型も一度定義すれば再利用しやすくなります。

2. keyof でオブジェクトのキーを型として取得する

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

ここで、keyuserオブジェクトのプロパティ名("name""age")でなければならないという制約がかかります。キーに基づいた型安全なコードが書けるので、エラーの発生を防ぐことができます。

3. おまけ

これまでのtypeofkeyofを組み合わせた使い方もあります。

const user = {
  name: "shige",
  age: 25
};

type UserKeys = keyof typeof user; // UserKeysは "name" | "age" になります

上記はtypeofを使わないとuser変数から直接型情報を取得することができないため、keyof単独で使用することはできません。
なので、typeofで変数から型情報を取得し、その型に対してkeyofを使ってキーの型を得ることで、オブジェクトのプロパティ名を利用できるようになります。

参考文献

https://qiita.com/tak001/items/bec3ab7c1bb4df52a7e7
https://www.typescriptlang.org/docs/handbook/2/keyof-types.html
https://www.typescriptlang.org/docs/handbook/2/typeof-types.html
https://zenn.dev/harryduck/articles/9d09b1c133f9cd

Discussion