keyofとvalueofを使いこなして、TypeScriptの型システムをさらに理解しよう
TypeScriptにおけるkeyofとvalueof
回答: はい、valueof
は存在しません。しかし、いくつかの方法で似たような機能を実現できます。
keyof
はオブジェクト型からそのプロパティ名の集合(union型)を取得します。
interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // "name" | "age"
const key: PersonKeys = "name"; // "name"または"age"のみ代入可能
interface Person {
name: string;
age: number;
}
type PersonValues = valueof<Person>; // string | number
const value: PersonValues = "John Doe"; // "John Doe"または100など代入可能
valueofの代替方法
- 手動で列挙:
type PersonValues = string | number;
keyof
とtypeof
の組み合わせ:**
type PersonValues = typeof Person[keyof Person];
- ユーティリティ型:**
type ValueOf<T> = T[keyof T];
type PersonValues = ValueOf<Person>;
valueof
は公式な型演算子ではありませんが、いくつかの方法で代替可能です。状況に合わせて最適な方法を選択してください。
補足
keyof
はオブジェクト型だけでなく、配列型やジェネリック型にも使用できます。typeof
は変数や型の実際の値を取得するために使用できます。
// インターフェース定義
interface Person {
name: string;
age: number;
isAdult: boolean;
}
// `keyof`の使用
type PersonKeys = keyof Person; // "name" | "age" | "isAdult"
// `valueof`の代替方法
// 1. 手動で列挙
type PersonValues1 = string | number | boolean;
// 2. `keyof`と`typeof`の組み合わせ
type PersonValues2 = typeof Person[keyof Person];
// 3. ユーティリティ型
type ValueOf<T> = T[keyof T];
type PersonValues3 = ValueOf<Person>;
// 各方法の動作確認
const key1: PersonKeys = "name"; // "name"または"age"または"isAdult"のみ代入可能
const value1: PersonValues1 = "John Doe"; // "John Doe"または100またはtrueなど代入可能
const value2: PersonValues2 = "John Doe"; // "John Doe"または100またはtrueなど代入可能
const value3: PersonValues3 = "John Doe"; // "John Doe"または100またはtrueなど代入可能
// オブジェクトの値へのアクセス
const person: Person = {
name: "John Doe",
age: 30,
isAdult: true,
};
const name: string = person.name; // "John Doe"
const age: number = person.age; // 30
const isAdult: boolean = person.isAdult; // true
実行結果
// 特になし
注意事項
- このコードはTypeScriptのバージョン4.1で動作確認しています。
- ユーティリティ型
ValueOf
は、自分で定義する必要があります。
keyof
とvalueof
は、オブジェクトリテラルやジェネリック型にも使用できます。- 詳細については、TypeScriptの公式ドキュメントを参照してください。
valueofを実現する他の方法
interface Person {
name: string;
age: number;
isAdult: boolean;
}
const person: Person = {
name: "John Doe",
age: 30,
isAdult: true,
};
const values: PersonValues = Object.values(person); // ["John Doe", 30, true]
type PersonValues = typeof values[number]; // string | number | boolean
interface Person {
name: string;
age: number;
isAdult: boolean;
}
const person: Person = {
name: "John Doe",
age: 30,
isAdult: true,
};
const values: PersonValues = Object.keys(person).map(key => person[key]); // ["John Doe", 30, true]
type PersonValues = typeof values[number]; // string | number | boolean
ユーティリティライブラリの使用
lodash
などのユーティリティライブラリには、valueof
に似た機能を提供する関数があります。
import { valueof } from "lodash";
interface Person {
name: string;
age: number;
isAdult: boolean;
}
const person: Person = {
name: "John Doe",
age: 30,
isAdult: true,
};
const values: PersonValues = valueof(person); // ["John Doe", 30, true]
type PersonValues = typeof values[number]; // string | number | boolean
- 简单的なケースでは、
Object.values
を使うのが最も簡単です。 - より複雑なケースでは、
keyof
とmap
の組み合わせを使う方が柔軟性があります。 - ユーティリティライブラリを使うと、コードを簡潔に書けますが、ライブラリの依存関係が増えてしまいます。
typescript types