TypeScriptのジェネリック型(Generics, 総称型)の指定方法について解説します。また、ジェネリック型を「利用しないケース」と「利用したケース」を比べて、どういったメリットがあるのか確認します。
ジェネリック型を利用しないケース
string
と number
を引数で受け取り、そのまま返す関数を例に考えます。
複数の関数を定義
2つ関数を作ります。
const testString = (x: string): string => x
const testNumber = (x: number): number => x
console.log(testString('Hello'))
console.log(testNumber(100))
関数の処理は同じなのに、複数の関数を定義しなければいけません。
anyを利用
any
を利用して実装してみます。
下記コードはTypeScriptのコンパイルでエラーとなりません。
const test = (x: any): any => x
console.log(test('Hello').length)
console.log(test(100).length)
コンパイル後のソースを実行してみます。
$ node test1.js
5
undefined
undefined
と表示されています。 test(100)
のときの戻り値は number
であり、string型の lengthプロパティ
が存在しないためです。
このように any
を利用した場合ですと、実行時にしか不具合に気づけません。
ジェネリック型を利用したケース
ジェネリック型を利用するには、以下のように記述します。
const test = <T>(x: T): T => x
console.log(test<string>('Hello').length)
console.log(test<number>(100).length)
コンパイルしてみます。
$ tsc test2.ts
test2.ts:4:31 - error TS2339: Property 'length' does not exist on type 'number'.
4 console.log(test<number>(100).length)
~~~~~~
Found 1 error.
ジェネリック型を利用することで、 以下の利便性を得ることができました。
- 1つの関数で定義できる
- 不具合があれば、コンパイル時点でエラーを知らせてくれる
ジェネリック型の利用方法
関数で利用
function test<T>(x: T) {
return x
}
アロー関数の場合、以下のように記述します。
const test = <T>(x: T): T => x
呼び出し|型を明示的に指定
呼び出し時に、<number>
<string>
のように型を明示的に指定して呼び出します。
const test = <T>(x: T): T => x
console.log(test<number>(100).length)
console.log(test<string>('Hello').length)
VSCodeの場合、赤波線でエラーを教えてくれます。
呼び出し|型推論
型指定を記述しなくても、引数の値だけを確認して自動で T
が何になるのかを判定してくれます。
const test = <T>(x: T): T => x
console.log(test(100).length)
console.log(test('Hello').length)
VSCodeの場合、赤波線でエラーを教えてくれます。
複数のジェネリック型を利用
下記コードには不具合があります。
let echo1 = <T>(x: T, y: T): void => {
console.log(x)
console.log(y)
}
echo1(100, 'Hello')
1つのジェネリック型に、引数で複数の型(number
と string
)を渡しているためコンパイルでエラーとなります。
$ tsc test1.ts
test1.ts:5:12 - error TS2345: Argument of type '"Hello"' is not assignable to parameter of type 'number'.
5 echo1(100, 'Hello')
~~~~~~~
Found 1 error.
複数のジェネリック型を利用したい場合には、以下のように記述します。
let echo2 = <T, U>(x: T, y: U): void => {
console.log(x)
console.log(y)
}
echo2(100, 'Hello')
VSCodeの場合、赤波線でエラーを教えてくれます。
クラスで利用
クラス名の後に <>
を追加します。
class test<T> {
xxx: T
}
let testNumber = new test<number>()
testNumber.xxx = 100
let testString = new test<string>()
testString.xxx = 'Hello'