このシリーズの概要
これまで、業務やプライベートで TypeScript を書いてきました👇 (例) しかし
なんとなく書いてきたので、キチンと理解する目的で書こうと思い、気になる単位ごとにまとめてアウトプットしようと思いました。
今回書くのは「総称型(ジェネリクス)」についてです。
総称型(ジェネリクス)の について
ジェネリック(形容詞)の意味は「一般的な、包括的な、汎用的な、総称的な」という意味があるそうです。
TypeScriptでも、そんな感じの意味で使われています。TypeScriptでは、どんな使われ方をするかみていきましょう。
例えば、ある関数を作成するとします。その関数の方は「引数を文字列を受け取ったら、戻り値も文字列で返す。引数を数値を受け取ったら、戻り値も数値で返す。」こんな関数を作りたい時の型の指定はどうすればいいでしょうか?
const echo = (params: number): number => params
const echo = (params: string): string => params
それぞれに型を指定するのはめんどくさい。としましょう。
このように、型が違うだけで引数で受けたデータをそのまま返り値として返している(同じような処理の関数)の型の指定を共通化できるのがジェネリクスという仕組みです。
型における変数のような機能を振る舞わせることで、型が違うだけの同じような処理の関数をいくつも作ることを防げます。
先ほど書いた関数をジェネリクスを用いて共通化させます。
関数定義にジェネリクスを利用する場合、関数名に続けて「<T>
」のようにT型をエイリアスとして指定します。
型エイリアスは略称らしい
諸説あるらしいですが、型エイリアスの略称は、TはTypeを表し、KはKey、EはElement、UはUnknownを表すらしいです。
先ほど書いた2つの関数を、型の指定にジェネリクスを使うことで共通化します。
const echo = <T>(params: T): T => params
// 大事なポイント 指定された型は全て同じ型になるということ(文字列を引数で渡す場合は、戻り値も文字列になる)
// どんな型でも使えるが、必ず渡された型に制約されます
注目するポイントは<T>
で、これが総称的な、もしくは汎用的な型として機能しています。
この関数を使う場合はこんな感じで使います。
console.log(echo<string>("test"))
console.log(echo<number>(10))
console.log(echo<boolean>(true))
// 型推論もできる
console.log(echo("test"))
console.log(echo(10))
console.log(echo(true))
ジェネリクスを使うことで、型が違うだけで関数を作るコストが省けましたね。
extendsを使って型に制約を付ける
特定の型のみに制限したい時はextends
を使います。
const echo = <T extends string>(params: T): T => params
console.log(echo("test")) // エラーにならない
console.log(echo(10)) // エラー文 Argument of type 'number' is not assignable to parameter of type 'string'.
複数の型定義
複数の型の指定も可能です。
const echo = <T, K>(params1: T, params2: K): K => params2
console.log(echo("test", 10))
以上です。
参考
アウトプット100本ノック実施中