JavaScript

【TypeScript】typeofとkeyofの使い方

typeofとは

typeofはすでにJavaScriptにある機能です。
JavaScriptとTypeScriptでどのような違いがあるか見ていきましょう。

JavaScriptのtypeof

JavaScriptのtypeofは、オペランドの型を返します。

typeof true; // 'boolean'
typeof 1; // 'number'
typeof 'text'; 'string'
typeof null; 'object'

オペランドがnullの場合、返り値が’object’になる点に注意が必要です。

TypeScriptのtypeof

TypeScriptの場合、JavaScriptのtypeofの機能に加え、返却値を型情報として使用することができます。

例えば、obj1というオブジェクトと同じプロパティ名を持ったオブジェクトを、obj2として複製するコードを記述します。

const obj1 = {
    foo: 'foo',
    bar: 'bar',
}

const obj2: typeof obj1 = {
    foo: 'foofoo',
    bar: 'barbar',
}

上記のように記述すると、obj1とobj2のプロパティ名を確実に同じにすることができます。
実際にコードを記述する際、obj2に型アノテーションを記述した時点で、obj2の型が適切に推論されていることがわかります。

また、他の型演算子と組み合わせることもできます。
下記コードでは、objオブジェクトのキーをユニオン型として取り出しています。
(keyofについては、次のセクションで解説しています)

const obj = {
    foo: 'foo',
    bar: 'bar',
}

type Key = keyof typeof obj; // "foo" | "bar"

keyofとは

keyofは型オブジェクトのプロパティ名をリテラル型として返却します。
複数のプロパティがある場合、リテラル型をユニオン型として返却します。
(型定義に対してのみ使用できます。変数等に対して使用することはできません。)

const obj = {
  foo: 'foo',
  bar: 'bar',
}

type Obj = typeof obj;
type Key = keyof Obj; // type Key = "foo" | "bar"

type MyKey = keyof typeof obj; // keyofとtypeofを続けて記述できる

具体的な使い方の一例として、関数の引数をオブジェクトのプロパティに限定することができます。

const language = {
  ja: 'japanese',
  en: 'english',
}

// (parameter) lang: "ja" | "en"
function translate(lang: keyof typeof language) {
 // 
}

translate("ja"); // ok
translate('ko'); // Argument of type '"ko"' is not assignable to parameter of type '"ja" | "en"'.