keyof typeof
TypeScriptで何を意味するのか教えてください
例:
enum ColorsEnum {
white = '#ffffff',
black = '#000000',
}
type Colors = keyof typeof ColorsEnum;
最後の行は次の行と同等です。
type Colors = "white" | "black"
しかし、それはどのように機能するのでしょうか?
typeof ColorsEnum
次のようなものを返して"Object"
、keyof "Object"
何も面白いことはしないだろうと予想していました。しかし、明らかに私は間違っています。
ベストアンサー1
keyof typeof
TypeScript での使用法を理解するには、まずリテラル型とリテラル型の和集合が何であるかを理解する必要があります。そこで、まずこれらの概念を説明し、次にkeyof
と をtypeof
個別に詳しく説明します。その後、 に戻ってenum
質問の内容に答えます。長い回答ですが、例は理解しやすいです。
リテラル型
TypeScript のリテラル型はstring
、 、number
、または のより具体的な型ですboolean
。たとえば、"Hello World"
は ですstring
が、 はstring
ではありません"Hello World"
。"Hello World"
は 型のより具体的な型なのでstring
、リテラル型です。
リテラル型は次のように宣言できます。
type Greeting = "Hello"
つまり、次のコードに示すように、型のオブジェクトには値Greeting
のみを設定でき、他の値や他の型の他の値を設定することはできません。string
"Hello"
string
let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi" // Error: Type '"Hi"' is not assignable to type '"Hello"'
リテラル型はそれ自体では役に立ちませんが、ユニオン型、型エイリアス、型ガードと組み合わせると強力になります。
以下はリテラル型の結合の例です。
type Greeting = "Hello" | "Hi" | "Welcome"
これで、 型のオブジェクトは、、、 のGreeting
いずれかの値を持つことができます。"Hello"
"Hi"
"Welcome"
let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi" // OK
greeting = "Welcome" // OK
greeting = "GoodEvening" // Error: Type '"GoodEvening"' is not assignable to type 'Greeting'
keyof
のみ
keyof
何らかの型は、リテラル型の和集合でT
ある新しい型を提供し、これらのリテラル型は のプロパティの名前です。結果の型は文字列のサブタイプです。T
たとえば、次のことを考慮してくださいinterface
。
interface Person {
name: string
age: number
location: string
}
keyof
型に対して演算子を使用すると、Person
次のコードに示すように新しい型が生成されます。
type SomeNewType = keyof Person
これは、型 のプロパティから作成されたSomeNewType
リテラル型 ( ) の結合です。"name" | "age" | "location"
Person
これで、次のタイプのオブジェクトを作成できますSomeNewType
:
let newTypeObject: SomeNewType
newTypeObject = "name" // OK
newTypeObject = "age" // OK
newTypeObject = "location" // OK
newTypeObject = "anyOtherValue" // Error...
keyof typeof
一緒にオブジェクトに
すでにご存知かもしれませんが、typeof
演算子はオブジェクトの型を示します。上記のインターフェースの例では、型はすでにわかっていたので、 type に対して演算子Person
を使用するだけで済みました。keyof
Person
しかし、オブジェクトの型がわからない場合、または次のように値だけがあってその値の型がわからない場合はどうすればよいでしょうか?
const bmw = { name: "BMW", power: "1000hp" }
ここは一緒に使うところですkeyof typeof
。
次のtypeof bmw
ようなタイプが提供されます:{ name: string, power: string }
そして、keyof
演算子は次のコードに示すようにリテラル型のユニオンを提供します。
type CarLiteralType = keyof typeof bmw
let carPropertyLiteral: CarLiteralType
carPropertyLiteral = "name" // OK
carPropertyLiteral = "power" // OK
carPropertyLiteral = "anyOther" // Error...
keyof typeof
にenum
TypeScript では、定数の型安全性を確保するために、コンパイル時には列挙型が型として使用されますが、実行時にはオブジェクトとして扱われます。これは、TypeScript コードが JavaScript にコンパイルされると、列挙型がプレーン オブジェクトに変換されるためです。したがって、上記のオブジェクトの説明はここでも当てはまります。質問で OP が示した例は次のとおりです。
enum ColorsEnum {
white = '#ffffff',
black = '#000000',
}
ここでは、ColorsEnum
実行時に型としてではなくオブジェクトとして存在します。そのため、keyof typeof
次のコードに示すように、演算子を一緒に呼び出す必要があります。
type Colors = keyof typeof ColorsEnum
let colorLiteral: Colors
colorLiteral = "white" // OK
colorLiteral = "black" // OK
colorLiteral = "red" // Error...