【TypeScript】オブジェクトや配列のキーや値をUnion型に変換する

更新日:2024/02/27

TypeScriptの型コンテキストに、オブジェクトまたは配列のプロパティ名や値をunion型に変換したものを指定したいことがあります。

そこで今回は、その方法をお伝えします。

 

typeof演算子とkeyof演算子

今回の記事では、typeof演算子とkeyof演算子を使用します。

typeof演算子は、変数やプロパティの型を返します。

let a = 100;
let b: typeof a;  // b は number型
type c = typeof a;  // c は number型

keyof演算子は、オブジェクトが持っているプロパティの名前をunion型で返します。

type t = keyof { value: number; text: string; 1:number}; // t は、"value" | "text" | 1

詳しい解説は、次の記事でお伝えしているので参考にしてみてください。

 

オブジェクトのプロパティ名(キー)をUnion型に変換

まずは、次のようにオブジェクトのプロパティ名をUnion型に変換する方法をお伝えします。

{ a:"e" , b:"f" , c:"g" }"a" | "b" | "c"

オブジェクトのプロパティ名をUnion型に変換するには、「 keyof typeof obj 」の式を使用します。

コード例

const obj ={
    a:"abc",
    b:"cde",
    c:"efg"
};

type ObjKeys =  keyof typeof obj; // "a" | "b" | "c"

解説

まず、typeofでオブジェクトを型に変換します。

type ObjKeysA = typeof obj; // ObjKeysAは次の型で定義される
                                          // { a:string, b:string, c:string }

次に keyof を適用します。
keyofは、 オブジェクト型からキーを抜き出して Union型 に変換してくれます。

type ObjKeys = keyof ObjKeysA; // "a" | "b" | "c"

ObjKeysAは typeof objなので、次のように展開できます。

type ObjKeys =  keyof typeof obj; // "a" | "b" | "c"

オブジェクトのキーをUnion型に変換するには、「keyof typeof obj」という式を使えばいいということがわかります。

使用例

次のコードは、オブジェクトのプロパティ名を引数として受け取る関数です。

const obj = {
    a:100,
    b:200
};
type ObjParamNames = keyof typeof obj;

function func( paramName:ObjParamNames ):number{
    return obj[paramName];
}

func("a");

本来ならオブジェクトに指定されたプロパティが存在するかどうかのチェックが必要です。
ですが、オブジェクトのキーをUnion型を使用することで、TypeScriptにチェックを丸投げしています。

 

オブジェクトのプロパティの型をUnion型に変換

オブジェクトのプロパティの型を、次のようにUnion型に変換する方法についてお伝えします。

{ a:"e" , b:1 , c:true }string | number | boolean

オブジェクトのプロパティの型をUnion型に変換するには、「 typeof obj[ keyof typeof obj ] 」の式を使用します。

コード例

const obj ={
    a:"abc",
    b:100,
    c:true
};

type ObjTypes =   typeof obj[ keyof typeof obj ]; // string | number | boolean

解説

オブジェクトに、配列形式で添え字をUnion型にして typeofを使うと プロパティの型をUnion型を返してくれます。

type aaa = typeof obj[ "a"|"b" | "c" ]; // string | number | boolean

string | number | boolean は、今回取得したい Union型です。
そこで、上記のオブジェクトから "a"|"b" | "c" を算出します。

前項の「オブジェクトのプロパティ名(キー)をUnion型に変換」で解説しましたが、「keyof typeof obj」という式で、取得できます。

type ObjTypesA =   keyof typeof obj; // "a" | "b" | "c"

この型を添え字に使って、Union型を取得します。

type ObjTypes =    typeof obj[ ObjTypesA ]; // string | number | boolean

ObjTypesAは、keyof typeof obj なので置き換えます。

type ObjTypes =    typeof obj[ keyof typeof obj ]; // string | number | boolean

オブジェクトのプロパティの型をUnion型に変換するには、「 typeof obj[ keyof typeof obj ] 」という式を使うといいことがわかりました。

使用例

次のコードは、前項の「オブジェクトのプロパティ名(キー)をUnion型に変換」と同じようなコードです。
しかし今回はプロパティの型が複数あるので、関数の戻り値の型を number型に決め打ちできません。

そこで、値の型の union型を使用します。

const obj = {
    a:100,
    b:"abc"
};
type ObjParamNames = keyof typeof obj;
type ObjParamTypes = typeof obj[ObjParamNames];

function func( paramName:ObjParamNames ):ObjParamTypes{
    return obj[paramName];
}

func("a");

 

オブジェクトのプロパティ値をUnion型に変換

オブジェクトのプロパティ値を、次のようにUnion型に変換する方法についてお伝えします。

{ a:"e" , b:"f" , c:"g" }"e" | "f" | "g"

オブジェクトのプロパティ値をUnion型に変換するには、オブジェクトにconstアサーションを適用してから、「 typeof obj[ keyof typeof obj ] 」の式を使用します。

コード例

const obj ={
    a:"abc",
    b:"cde",
    c:"efg"
} as const;

type ObjValues =   typeof obj[ keyof typeof obj ]; // "abc" | "cde" | "efg"

解説

コード上の as const は、オブジェクトリテラルのプロパティ値を読み込み専用(readonly)に設定します。
そして、プロパティの型をリテラル型にします。

次のように、型付けしたものと同じイメージです。

const obj :{
    readonly a:"abc",  // "abc"というリテラル型
    readonly b:"cde", // "cde"というリテラル型
    readonly c:"efg"  // "efg"というリテラル型
} = {
    a:"abc",
    b:"cde",
    c:"efg"
};

as constについては、次の記事で紹介しているので参考にしてみてください。
【TypeScript】変数宣言constとas constの違い

後は、前項の「オブジェクトのプロパティの型をUnion型に変換」と同じです。
前項は string型やnumber型などでしたが、今回はリテラル型になっただけです。

typeof obj[ keyof typeof obj ]で、求めることができます。

type ObjKeys =    typeof obj[ keyof typeof obj ]; // "abc" | "cde" | "efg"

注意点

as constは、変数に使用できません。
使うとエラーです。

const obj2 = obj as const; // A 'const' assertions can only be applied to references to enum members, or string, number, boolean, array, or object literals.

※エラー内容:「const」アサーションは、列挙メンバー、または文字列、数値、ブール、配列、またはオブジェクト リテラルへの参照にのみ適用できます。

使用例

次のコードは、受け取った引数と同じ値を持つプロパティが、オブジェクトにあるかどうかを確認する関数を定義しています。

const obj = {
    a:100,
    b:"abc"
} as const;

type ObjParamTypes = typeof obj[keyof typeof obj];

function isValue( value:any ):value is ObjParamTypes {
    return Object.values(obj).some(e=>e===value);
}

let v = 100;

if( isValue(v) ){
   // v は 
}else{

}

isは、戻り値は boolean型 だが、 呼び出し元で型ガードとして解釈可能だということを意味しています。

 

配列要素の型をUnion型に変換

配列要素の型をUnion型に変換してみます。

typeof array[number] 」で求めることができます。

コード例

const array =["abc","def",100,true];

type ArrayTypes =   typeof array[number]; // string | number | boolean

解説

配列の添え字に number を指定すると、全てのインデックス要素を取得できます。
その結果に対して typeof演算子を適用するとUnion型を取得できます。

注意点

配列内の順番で型を取り出すような錯覚をしがちです。
実際には同じ型は一つにまとめられます。

 

配列要素の値をUnion型に変換

配列要素の値をUnion型に変換してみます。

配列に as const を適用した後、「 typeof array[number] 」で求めることができます。

コード例

const array =["abc","def",100,true] as const;

type ArrayTypes =   typeof array[number]; // true | "abc" | "def" | 100

解説

配列に as const を適用すると、各要素の型はリテラル型になります。
その型に対して、前項と同じ式を適用しています。

更新日:2024/02/27

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。