型を使い回す

INPUT · スライド

型引数を書く関数

01 / 05

型ごとに同じ関数を書くのはつらい

「配列を受け取って、最初の1件を返す関数」を作りたいとしよう。文字列の配列にも、数値の配列にも使いたい。

今のままだと、中身がまったく同じ関数を、型のぶんだけ書くことになってしまう。

function saishoS(list: string[]): string {  return list[0];}function saishoN(list: number[]): number {  return list[0];}console.log(saishoS(["あ", "い"]));console.log(saishoN([3, 5]));

実行結果

あ
3

02 / 05

`any[]` にすると型が消える

では any[] にしてしまえばいいのかというと、それはやめておこう。「何でもよい」と宣言すると、戻り値が何なのかも分からなくなるからだ。

下のコードは型のエラーが1つも出ない。でも s に入っているのは数値のほうだよ。文字列のつもりで length を見ると、答えは undefined になる。

function saisho(list: any[]): any {  return list[0];}const s: string = saisho([10, 20]);console.log(s.length);

実行結果

undefined

03 / 05

型引数 `<T>` を書く

関数名のうしろに <T> と書くと、「中身の型はここでは決めない。呼ぶ人が決める」という意味になる。

あとは T を、ふつうの型の名前と同じように使えばいいよ。

  • 受け取るのは T[]
  • 返すのは T
function saisho<T>(list: T[]): T {  return list[0];}console.log(saisho(["あ", "い"]));console.log(saisho([3, 5]));

実行結果

あ
3

04 / 05

渡した型が戻り値まで伝わる

T は呼ばれたときに、実際の型に置きかわる。文字列の配列を渡せば戻り値も文字列になるよ。

だから、返ってきたものを数値の変数に入れようとすると止めてくれる。any では素通りしてしまったところだ。

function saisho<T>(list: T[]): T {  return list[0];}const n: number = saisho(["あ", "い"]);

実行結果

型のエラー: 型 'string' を型 'number' に割り当てることはできません。

05 / 05

`T` はただの名前

T に決まった意味はない。型(type)の頭文字を借りているだけで、べつの名前にしても動くよ。ただ T と書く人がいちばん多いので、合わせておくと読みやすい。

相手は配列じゃなくてもいい。値をそのまま返すだけの関数にも使える。ここから自分で書いてみよう。

function sonomama<T>(atai: T): T {  return atai;}console.log(sonomama("あめ"));console.log(sonomama(12));console.log(sonomama(true));

実行結果

あめ
12
true