はじめに
先日TypeScriptの最新バージョンが5に変更されました。リリースノートはこちらで、変更や修正の詳細はこちらの記事に記載されています。
この記事ではTypeScript5で追加されたconst type parameters
という機能について解説します。
const type parameters
とは
const type parameters
はTypeScriptが型推論を行うときに一般的な型ではなく、より具体的な型に推論させるような機能です。
string
のような型ではなく'hello'
のような型、readonly number[]
ではなく[1, 2, 3]
のような型に推論させます。
例
例としてオブジェクトの一部から値を取り出すようなケースを考えます。
const getLangs = <T extends { langs: readonly string[] }>(
args: T,
): T['langs'] => {
return args.langs;
};
const langs = getLangs({ langs: ['ja', 'en', 'fr'] });
langs
の型はreadonly string[]
になります。
関数の戻り値であるlangs
の型を代入したオブジェクトに応じてreadonly ['ja', 'en', 'fr']
のようにしたいとします。
そのためには、関数の定義方法を変更するのではなく呼び出すたびにconst assertion
を用いて記述することで達成されます。
const langs = getLangs({ langs: ['ja', 'en', 'fr'] as const });
他にも関数側でこの挙動を実現するために、以下のように型をこねくり回して記述できます。
type Narrowable = string | number | boolean | symbol | object | undefined | void | null | {};
const getLangs = <N extends Narrowable, const T extends (N | T)[] | []>(
args: { langs: T },
): T => {
return args.langs;
};
const langs = getLangs({ langs: ['ja', 'en', 'fr'] });
(他にも方法があるかもしれませんが)このようにこれまでは、実現したい関数の挙動を実現するために呼び出す側で記法の矯正を行う保守性に優れない実装になったり、複雑で可読性の低いコードになってしまいました。
const type parameters
はこの挙動を関数側で簡単に実現可能にする機能です。
const getLangs = <const T extends { langs: readonly string[] }>(
args: T,
): T['langs'] => {
return args.langs;
};
const langs = getLangs({ langs: ['ja', 'en', 'fr'] });
行った変更は型変数の宣言前に新たな修飾子const
を配置した点です。これだけでlangs
の型はreadonly ['ja', 'en', 'fr']
になります。
注意点
呼び出したパラメータに直接値を渡さなければ具体的な方に推論されないことに注意してください。
const obj = { langs: ['ja', 'en', 'fr'] };
const langs = getLangs(obj);
obj
を作成した時点でobj
の型が{ langs: string[] }
に推論されてしまっていることが原因です。
直接代入するか、
const obj = { langs: ['ja', 'en', 'fr'] as const };
推論される型がreadonly ['ja', 'en', 'fr']
となるようにobj
を作成してください。