この記事では、TypeScriptにおけるconst type parameter
という概念と、それがどのようにas const
(constアサーション)の使用を省略できるかについて説明します。これは初心者にとって少し複雑に感じるかもしれませんが、実際には非常に便利で強力な機能です。では、早速見ていきましょう。
基本的な関数の例
まずは、基本的な関数を2つ見てみましょう。
function withoutConst<T>(value: T): T {
return value;
}
function withConst<const T>(value: T): T {
return value;
}
ここで、withoutConst
とwithConst
の2つの関数があります。これらはどちらも引数をそのまま返す非常にシンプルな関数ですが、重要な違いが一つあります。それは、withConst
関数にconst T
という型パラメータが使われている点です。
withoutConstの動作
withoutConst
関数を使うと、型はより一般的な形で推論されます:
const value1 = withoutConst(123);
// ^? const value1: 123
const value2 = withoutConst({ num: 123 });
// ^? const value2: { num: number; }
const value3 = withoutConst([1, 2, 3]);
// ^? const value3: number[]
ここでは、数値、オブジェクト、配列の3つの異なる型の値をwithoutConst
に渡しています。この場合、TypeScriptはそれぞれの型を推論しますが、オブジェクトや配列はその構成要素が変更可能であると見なされます(つまり、readonly
ではありません)。
constアサーションの使用
もし、変更不可能な(immutableな)型を確保したい場合、constアサーション
を使うことができます。これはas const
と記述します。例えば:
const value1 = withoutConst(123 as const);
// ^? const value1: 123
const value2 = withoutConst({ num: 123 } as const);
// ^? const value2: { readonly num: 123; }
const value3 = withoutConst([1, 2, 3] as const);
// ^? const value3: readonly [1, 2, 3]
ここで、as const
を使うことで、TypeScriptに対して値が変更不可能であることを明示しています。これにより、オブジェクトや配列はreadonly
として扱われます。また、num
の型は123
のようなリテラル型にもなります。更に、配列は単なる配列型(T[]
)ではなくタプル型として扱われます。
withConstの威力
const type parameter
を使うwithConst
関数を使うと、as const
を省略できます。つまり、同じ振る舞いをもっと簡単に実現できるのです。
const value1 = withConst(123);
// ^? const value1: 123
const value2 = withConst({ num: 123 });
// ^? const value2: { readonly num: 123; }
const value3 = withConst([1, 2, 3]);
// ^? const value3: readonly [1, 2, 3]
この場合、withConst
は自動的にその引数が変更不可能であると推論し、そのためas const
を付ける必要がありません。これにより、コードがよりシンプルで読みやすくなります。
まとめ
const type parameter
を使用することで、TypeScriptの型システムの強力さをさらに引き出すことができます。特に、as const
を多用している場合には、この機能を使ってコードをよりシンプルに保つことができます。
ちなみに、本稿で扱ったサンプルコードはTypeScript Playgroundにあります: